进阶
1. 类型别名
// 类型别名用来给一个类型起个新名字。typeName=string;typeNameResolver=()=>string;typeNameOrResolver=Name|NameResolver;functiongetName(n: NameOrResolver): Name{if(typeofn==='string'){returnn;}else{returnn();}}2. 字符串字面量类型
// 字符串字面量类型用来约束取值只能是某几个字符串中的一个。// 类型别名与字符串字面量类型都是使用 type 进行定义。typeEventNames='click'|'scroll'|'mousemove';functionhandleEvent(ele: Element,event: EventNames){// do something}handleEvent(document.getElementById('hello'),'scroll');// 没问题handleEvent(document.getElementById('world'),'dblclick');// 报错,event 不能为 'dblclick'3. 枚举
// 枚举(Enum)类型用于取值被限定在一定范围内的场景,比如一周只能有七天,颜色限定为红绿蓝等。 枚举使用 enum 关键字来定义:// 枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射:enumDays{Sun,Mon,Tue,Wed,Thu,Fri,Sat};// 枚举项有两种类型:常数项(constant member)和计算所得项(computed member)。enumColor{Red,Green,Blue="blue".length};// 常数枚举// 常数枚举与普通枚举的区别是,它会在编译阶段被删除,并且不能包含计算成员。constenumDirections{Up,Down,Left,Right}letdirections=[Directions.Up,Directions.Down,Directions.Left,Directions.Right];4. 类
/* TypeScript 可以使用三种访问修饰符(Access Modifiers),分别是 public、private 和 protected。 public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的 private 修饰的属性或方法是私有的,不能在声明它的类的外部访问 protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的*/// readonly 只读属性关键字,只允许出现在属性声明或索引签名或构造函数中。classAnimal{// public readonly name;publicconstructor(publicreadonlyname){// this.name = name;}}// 抽象类 abstract 用于定义抽象类和其中的抽象方法。// 1. 不允许被实例化abstractclassAnimal2{publicname;publicconstructor(name){this.name=name;}publicabstractsayHi();}leta=newAnimal2('Jack');// 报错// 2. 抽象类中的抽象方法必须被子类实现abstractclassAnimal3{publicname;publicconstructor(name){this.name=name;}publicabstractsayHi();}// 未实现sayHi方法会报错classCatextendsAnimal3{// public sayHi() {// console.log(`Meow, My name is ${this.name}`);// }}letcat5=newCat('Tom');5. 类与接口
// 1. 类实现接口 /* 一般来讲,一个类只能继承自另一个类,有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口 (interfaces),用 implements 关键字来实现。这个特性大大提高了面向对象的灵活性 */interfaceAlarm{alert(): void;}classDoor{}classSecurityDoorextendsDoorimplementsAlarm{alert(){console.log('SecurityDoor alert');}}classCarimplementsAlarm{alert(){console.log('Car alert');}}// 一个类可以实现多个接口: class Car implements Alarm, Light// 2. 接口继承接口interfaceLightableAlarmextendsAlarm{lightOn(): void;lightOff(): void;}// 3. 接口继承类// 常见的面向对象语言中,接口是不能继承类的,但是在 TypeScript 中却是可以的:classPoint{x: number;y: number;constructor(x: number,y: number){this.x=x;this.y=y;}}interfacePoint3dextendsPoint{z: number;}letpoint3d: Point3d={x: 1,y: 2,z: 3};6. 泛型
// 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。// 我们在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了。functioncreateArray<T>(length: number,value: T): Array<T>{letresult: T[]=[];for(leti=0;i<length;i++){result[i]=value;}returnresult;}createArray<string>(3,'x');// ['x', 'x', 'x']// 1. 定义泛型的时候,可以一次定义多个类型参数:functionswap<T,U>(tuple: [T,U]): [U,T]{return[tuple[1],tuple[0]];}swap([7,'seven']);// ['seven', 7]// 2. 泛型约束// 我们可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量。这就是泛型约束:interfaceLengthwise{length: number;}functionloggingIdentity<TextendsLengthwise>(arg: T): T{console.log(arg.length);returnarg;}// 3. 泛型接口interfaceCreateArrayFunc<T>{(length: number,value: T): Array<T>;}letcreateArray1: CreateArrayFunc<any>;createArray1=function<T>(length: number,value: T): Array<T>{letresult: T[]=[];for(leti=0;i<length;i++){result[i]=value;}returnresult;}createArray(3,'x');// ['x', 'x', 'x']// 4. 泛型参数的默认类型functioncreateArray2<T=string>(length: number,value: T): Array<T>{letresult: T[]=[];for(leti=0;i<length;i++){result[i]=value;}returnresult;}7. 声明合并
// 如果定义了两个相同名字的函数、接口或类,那么它们会合并成一个类型: 合并的属性的类型必须是唯一的interfaceAlarm1{price: number;}interfaceAlarm1{price: number;// 虽然重复了,但是类型都是 `number`,所以不会报错weight: number;}interfaceAlarm2{price: number;}interfaceAlarm2{price: string;// 类型不一致,会报错weight: number;}
进阶
1. 类型别名
2. 字符串字面量类型
3. 枚举
4. 类
5. 类与接口
6. 泛型
7. 声明合并