数据类型
- 布尔值
- 数字
- 字符串
- 数组
元组(Tuple)
表示已知元素数量和类型的数组,越界元素使用联合类型替代
枚举(enum)
包含若干个枚举成员,和枚举值与枚举名的双向映射,枚举较为特殊,他的编译不是减量的,而且常数枚举会被删除
任意值
any类型的值会直接通过编译阶段的检查
空值(void)
默认情况下null
和undefined
是所有类型的子类型
null和undefined
never
类型断言
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| let isDone: boolean = false; let a: number = 0xf00d; let greeting: string = `hello,i am ${name}`; let list: number[] = [1, 2, 3]; let list: Array<number> = [1, 2, 3]; let x: [string, number]; x = ['hello', 2]; x = [2, 'hello']; x[3] = 'hi'; x[3] = 3; x[3] = false; enum Color {Red = 6, Green, Blue}; let c: Color = Color.Green; let notSure = 2; let list: any[] = [1, true, "free"]; let unusable: void = undefined; let unusable: void = null; let a: number = null; let b: string = undefined;
|
接口
我理解相当于制定的规则,也可用于描述函数类型
- 不检查属性的顺序
- 接口里的属性并非都是必须的
- 名字后加?表示可选属性
- 属性名前加readonly则该属性被指定为只读属性
- 对象字面量会被特殊对待而且会经过 额外属性检查,当将它们赋值给变量或作为参数传递的时候。 如果一个对象字面量存在任何“目标类型”不包含的属性时,你会得到一个错误。使用类型断言可以绕过这个问题,将对象赋值给另外一个值也可以绕开对象字面量的检查
- 也可用于描述函数类型,这时不会检查参数的名字,而检查函数返回值是否与接口中匹配
1 2 3 4 5 6 7 8 9
| interface FuncA { (a: string, b: number): string } let newFuncA: FuncA; newFuncA = function (a: string, b: number) { return `${a}b`; }
|
- 可索引的类型:可索引类型具有一个 索引签名,它描述了对象索引的类型,还有相应的索引返回值类型
1 2 3 4 5 6 7 8 9
| interface StringArray{ [index: number]: string; } let arr: StringArray = ['hello', 'world']; arr[1];
|
- 接口也可以用来描述类,接口中描述的方法在类里去实现它
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| interface ClockInterface { currentTime: Date; setDate (d: Date); } class Clock implements ClockInterface { currentTime: Date; setDate(d: Date) { this.currentTime = d; } constructor(h: number, m: number) { } }
|
函数
函数类型包括两部分:参数类型和返回值类型。
- ts中的函数参数都是必传的,编译器会检查是否每个参数都传入了值
- 在参数后添加? 可设置该参数为可选参数
- 也可以为参数设置默认值
- 剩余参数 restOfName(对比js中的arguments,arguments表示传入函数的所有参数,在ts中,restOfName表示剩余的参数)
1 2 3 4 5
| function buildName(firstName: string, ...restOfName: string[]) { return firstName + " " + restOfName.join(" "); } let employeeName = buildName("Joseph", "Samuel", "Lucas", "MacKinzie");
|
1 2 3 4 5 6 7 8 9
| function pickCard(x): any { if (typeof x == "object") { } else if (typeof x == "number") { } }
|
类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Animal { name:string; constructor(theName: string) { this.name = theName; } able(skill: string) { console.log(`${this.name} is able to ${skill}.`); } } class Cat extends Animal { constructor(name: string) { super(name); } able(skill) { super.able(skill); } } let tom = new Cat("tom"); tom.able("miaomiao");
|
修饰符(public/private/protect/readonly)
plublic
ts 中,成员默认为public
的, 当然,我们也可以显式的将成员标记为 public 的
private
当成员被标记成private
时,它就不能在声明它的类的外部访问
1 2 3 4 5 6 7 8 9 10 11 12
| class Cat extends Animal { constructor(name: string) { super(name); } private catchMouserNo: number; able(skill) { super.able(skill); } } let tom = new Cat("tom"); tom.able("miaomiao"); tom.catchMouserNo;
|
protected
与 private
类似,不能在声明它的类外使用,但是在派生类中仍然可以访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| class Animal { public name: string; protected age: number; public constructor(theName: string, age: number) { this.name = theName; this.age = age; } } class Cat extends Animal { constructor(name: string, age: number) { super(name, age); } public showAge() { console.log(this.age); } } let tom = new Cat("tom", 2); tom.showAge(); new Animal("dog", 12).age;
|
PS: 构造函数也可以被标记成protected
。 这意味着这个类不能在包含它的类外被实例化,但是能被继承
readonly
readonly
修饰符将属性设置为只读的,只读属性只能在声明时或构造函数中进行初始化
参数属性
给构造函数参数添加访问修饰符,可以将声明和赋值合并在一起
可以将上面的 Animal 类用如下方式改写
1 2 3
| class Animal { public constructor(public theName: string, protected age: number) {} }
|
存取器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| class Animal { private _age: number; set age(age: number){ if (age > 10) { console.log('it is too old'); } else { this._age = age; } } get age() { return this._age; } } let dog = new Animal(); dog.age = 10; dog._age = 10;
|
相当于是通过 get 和 set 方法来简洁的操作成员变量,提高了变量的安全性(我们可以在存取值时做一些逻辑判断的工作)
静态属性
静态属性存在与类本身上而并不是类的实例上我们可以认为类具有 实例部分与静态部分这两个部分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Animal { static info = { type: "pet", maxAge: 20 }; getInfo(): void { console.log(Animal.info.type, Animal.info.maxAge); } } let catA = new Animal(); catA.getInfo(); var Animal = (function () { function Animal() { } Animal.prototype.getInfo = function () { console.log(Animal.info.type, Animal.info.maxAge); }; return Animal; }()); Animal.info = { type: "pet", maxAge: 20 }; var catA = new Animal(); catA.getInfo();
|
抽象类
抽象类作为其他派生类的基类,abstract
关键字用于声明抽象类以及抽象类中的抽象方法
1 2 3 4 5 6 7 8 9 10 11 12 13
| abstract class Animal { abstract able(): void; } class Cat extends Animal { able(): void { console.log("cat can miaomiao!"); } } let catA = new Cat(); catA.able();
|
PS:这里的派生类 Cat 必须要包含父类 Animal 的抽象方法的实现,否则 ts 将给出错误提示
泛型
可用于编写可复用的组件,使组件可以支持多种的数据类型
场景:写一个方法 使得传入的参数类型和返回值得类型保持一致
1 2 3 4 5 6 7 8 9 10
| function identity<T>(arg: T): T { return arg; } let a = identity<number>(123); let b = identity<string>("this is a string"); let c = identity<boolean>(false); let d = identity<number[]>([1, 2, 3, 4]); console.log(a, b, c, d);
|
这里使用了一个类型变量 T ,T帮助我们捕获用户传入的类型,我们把这个 identity 函数叫做泛型函数
我们也可以在使用 identity 函数时不传入类型,因为编译器会为我们进行类型推论
1 2
| let a1 = identity(123); let b1 = identity("this is a string");
|
泛型接口
1 2 3 4 5 6 7 8 9 10
| interface GenericIdentityFn<T> { (arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identity; let myIdentity1: GenericIdentityFn<string> = identity;
|
这里传入类型参数来指定泛型类型
泛型类型
1 2 3 4 5 6 7 8 9 10 11 12
| class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function (x, y) { return x + y; }; let a = new GenericNumber<string>(); a.zeroValue = 'string!!'; a.add = function (x, y) { return x + y };
|
泛型类约束的是类的实例部分的类型,静态属性不能使用这个泛型类型。
枚举
包含若干个枚举成员,和枚举值与枚举名的双向映射,枚举较为特殊,他的编译不是减量的,而且常数枚举会被删除
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| enum Direction { Up = 1, Down, Left, Right } let down = Direction.Down; let nameOfDown = Direction[down]; console.log(down); console.log(nameOfDown); var Direction; (function (Direction) { Direction[Direction["Up"] = 1] = "Up"; Direction[Direction["Down"] = 2] = "Down"; Direction[Direction["Left"] = 3] = "Left"; Direction[Direction["Right"] = 4] = "Right"; })(Direction || (Direction = {})); var down = Direction.Down; var nameOfDown = Direction[down]; console.log(down); console.log(nameOfDown);
|
1 2 3 4 5 6 7 8 9
| const enum Direction { Up = 1, Down, Left, Right } let list = [Direction.Up, Direction.Left];
|
类型的兼容
接口的兼容性原则是:如果 x 要兼容 y ,那么 y 至少具有与 x 相同的属性(目标的成员会被一一检查)
1 2 3 4 5 6 7 8 9 10
| interface Struc { a: Number }; let x: Struc; let y = { a: 111, b: 'str1'}; x = y; y = x;
|
在js中,函数参数并不是全部都是必传的,所以在ts中,如果 x 要兼容 y ,x 的每个参数必须要在 y 中找的对应类型的参数
1 2 3 4 5
| let y = (a: number) => 0; let x = (b: number, s: string) => 0; x = y; y = x;
|
对于返回值类型,x 若要兼容 y ,那么 y 的返回值必须是 x 的返回值得子集
1 2 3 4 5
| let x = () => ({name: 'Alice'}); let y = () => ({name: 'Alice', location: 'Seattle'}); x = y; y = x;
|
命名空间
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| namespace Validation { export interface StringValidator { isAcceptable(s: string): boolean; } const lettersRegexp = /^[A-Za-z]+$/; const numberRegexp = /^[0-9]+$/; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string) { return lettersRegexp.test(s); } } export class ZipCodeValidator implements StringValidator { isAcceptable(s: string) { return s.length === 5 && numberRegexp.test(s); } } } var Validation; (function (Validation) { var lettersRegexp = /^[A-Za-z]+$/; var numberRegexp = /^[0-9]+$/; var LettersOnlyValidator = (function () { function LettersOnlyValidator() { } LettersOnlyValidator.prototype.isAcceptable = function (s) { return lettersRegexp.test(s); }; return LettersOnlyValidator; }()); Validation.LettersOnlyValidator = LettersOnlyValidator; var ZipCodeValidator = (function () { function ZipCodeValidator() { } ZipCodeValidator.prototype.isAcceptable = function (s) { return s.length === 5 && numberRegexp.test(s); }; return ZipCodeValidator; }()); Validation.ZipCodeValidator = ZipCodeValidator; })(Validation || (Validation = {}));
|
三斜线指令