多数例子参照于https://ts.xcatliu.com/TS入门教程
原始数据类型
布尔值、数值、字符串、null、undefined以及Symbol
TS中定义各种类型
布尔值
let isDone: boolen = true;
在JavaScript中Boolean创建的对象不是布尔值,事实上new Boolean()返回的是一个Boolean对象
数值
使用number定义数值类型
let num: number = 6; let binary: numner = 0xf00d; // 表示二进制,也可以定义为八进制,十进制
字符串
使用string定义字符串
let name: string = 'Tom';
空值
JavaScript里面没有空值(Void)的概念,在TypeScript中,可以用void表示没有任何返回值的函数
function alertName(): void { alert('My name is Tom'); }
这里声明一个void类型的变量没有什么用,因为只能将它赋值为undefined和null
Null和Undefined
在typescript中,可以使用null和undefined来定义这两个原始数据类型:
let u: undefined = undefined; let n: null = null;
与void的区别就是undefined和null是所有类型的子类型,也就是说undefined类型的变量,可以赋值给number类型的变量;但是void不能这样做,会报错。
任意值
如果一个普通类型,在赋值过程中改变类型是不被允许的,会报错。
但是如果是any类型,则允许被赋值为任意类型。
在任意值上访问任何属性都是允许的,也允许调用任何方法。
可以认为,声明一个变量为任意值之后,对它的任何操作,返回的内容的类型都是任意值。
let anyValue: any = 1; anyValue = 'any';
未声明类型的变量
变量如果在声明的时候,未指定其类型,那么他会被识别为任意值类型:
let something; something = 'seven'; something = 7;
类型推论
如果没有明确的指定类型,那么TypeScript会依照类型推论的规则推断出一个类型
let noneValue = 'seven'; noneValue = 7; // 这样会报错 // 上面的代码就是 let noneValue: string = 'seven'; noneValue = 7;
TypeScript会在没有明确的指定类型的时候推测出一个类型,这就时候类型推论。
如果定义的时候没有赋值,不管之后有没有赋值,都会被推断成any类型而完全不被类型检查。
联合类型
表示取值可以为多种类型中的一种。
let nameNumber: string | number; nameNumber = 'seven'; nameNumber = 7;
当typescript不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型里共有的属性或方法。
联合类型的变量在被赋值的时候,会根据类型推论的规则推断出一个类型。
接口
在面向对象语言中,接口(interfaces)是一个很重要的概念,它是对行为的抽象,而具体实现是由类(classes)去实现(implement)。
TypeScript中接口是对类的一部分进行抽象以外,也常用于对(对象的形状(Shape))进行描述。
赋值的时候,变量的形状必须和接口的形状保持一致
interface Person { name: string, age: number } let tom: Person = { name: 'Tom', age: 25 } // 约束tom的形状必须和接口Person一致 // 多一些属性和少一些属性都是不允许的
可选属性
有时候我们希望不要完全匹配一个形状,那么可以用可选属性:
interface Person { name: string, age?: number } let tom: Person { name: 'Tom' } // 可选属性的含义是该属性可以不存在,但是还是不能添加未定义属性
任意属性
有时候我们希望一个接口可以有任意属性
interface Person { name:string, age?: number, [propName: string]: any } let tom: Person = { name: 'Tom', gender: 'male' }
一旦定义了任意属性的类型那么确定属性和可选属性的类型都必须是他的类型的子集
interface Person { name: string; age?: number; [propName: string]: string; } let tom: Person = { name: 'Tom', age: 25, gender: 'male' }; // 会报错 任意属性的值允许是string,但是可选属性age的值却是number
只读属性
有时候我们希望对象中的一些字段只能在创建的时候被赋值,那么可以用readonly定义只读属性
interface Person { readonly id: number; name: string; age?: number; [proName: string]: any; } let tom: Person = { id: 89111, name: 'Tom', gender: 'male' } tom.id = 11111; // 只读属性约束存在第一次给对象赋值的时候,而不是第一次给只读属性赋值的时候 // 如果上述没有给id第一赋值也会报错
数组类型
最简单的方法是使用 类型+ 方括号 来表示数组:
let nowNumber: number[] = [1, 2, 3, 4, 5]; // 数组中不允许出现其他的类型
数组的一些方法和参数也会根据数组在定义是约定的类型进行限制
let nowNumber: number[] = [1, 2, 3, 4, 5]; nowNumber.push('8'); // 这里会报错 因为push方法只允许传入number类型参数,但是却传了一个"8"类型的参数,
数组泛型
我们也可以使用数组泛型(Array Generic)Array<elemType>来表示数组:
let nowArray: Array<number> = [1, 1, 2, 3, 5];
用接口来表示数组
interface NumberArray { [index: number]: number; } let NumberArray = [1, 2, 3, 5]; // NumberArray 表示只要索引的类型是数字,那么值的类型就必须是数字
类数组
类数组不是数组类型,比如arguments。
function sum() { let args: number[] = arguments } // arguments 实际上是一个类数组,不能用普通的数组方式来描述,应该使用接口
function sum() { let args: { [index: number]: number; length: number; callee: Function; } = arguments; } // 我们除了约束当索引的类型是数字时,值的类型必须是数字之外,也约束了它还有length // 和callee连个属性
实际上类数组都有自己的接口定义,如:IArguments,NodeList,HTMLCollection
any在数组中的应用
let list: any[] = ['111', 222, {age: 18}]; any表示数组中允许出现任意类型
函数声明
一个函数的输入与输出在TypeScript中对其进行约束,需要把输入和输出都考虑到
function sum(x: number, y: numbe): number { return x + y; } // 输入多余的参数,是不被允许的 会报错
函数表达式
如果要我们写一个函数表达式
let mySum = function (x: number, y: number): number { return x + y; };
这样是可行的,但是上面代码只对等号右侧的匿名函数进行类型定义,而等号左边的mySum,是通过赋值操作进行类型推断出来的,如果需要我们需要手动给mySum添加类型。
let mySum: (x: number, y: number) => number = function (x: number, y: number): number { return x + y; };
在TypeScript的类型定义中,=>用来表示函数的定义,左边是输入类型,需要用括号括起来,右边是输出类型。
在ES6中,=>叫做箭头函数。
用接口定义函数的形状
interface SearchFunc { (source: string, subString: string): boolean; }
let mySearch: SearchFunc; mySearch = function(source: string, subString: string) { return source.search(subString) !== -1; }
采用函数表达式接口定义函数的方式时,对等号左侧进行类型限制,可以保证以后对函数名赋值时保证参数个数,参数类型,返回值类型不变。
可选参数
定义可选参数与接口中类似,我们用?表示可选的参数:
function buildName(firstName: string, lastName?: string) {
if (lastName) {
return firstName + ' ' + lastName;
} else {
return firstName;
}
}
let tomcat = buildName('Tom', 'Cat'); let tom = buildName('Tom');
// 可选参数后面不允许再出现必须参数
参数的默认值
在ES6中我们允许给函数的参数添加默认值,TypeScript会将添加默认值的参数识别为可选参数:
function buildName(firstName: string, lastName: string = 'Cat') {
return firstName + ' ' + lastName;
}
let tomcat = buildName('Tom', 'Cat');
let tom = buildName('Tom');
// 此时就不受可选参数必须接在必需参数后面的限制了
剩余参数
ES6中们可以使用...rest的方式获取函数中的剩余参数(rest参数):
function push(array: any[], ...items: any[]) {
items.forEach(function(item) { array.push(item); });
}
let a = []; push(a, 1, 2, 3);
// items是一个数组,所以我们可以用数组的类型来定义它
重载
重载允许一个函数接收不同数量或类型的参数时,做出不同的处理
function reverse(x: number | string): number | string {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}
// 这个函数不能够精准的表达,输入为数字的时候,输出也应该为数字,输入为字符串的时候,输出也应该是字符串 // 这个时候我们可以使用重载来定义多个reverse的函数类型
function reverse(x: number): number; function reverse(x: string): string;
function reverse(x: number | string): number | string | void {
if (typeof x === 'number') {
return Number(x.toString().split('').reverse().join(''));
} else if (typeof x === 'string') {
return x.split('').reverse().join('');
}
}