二、进阶
1.类型别名
类型别名用来给一个类型起个新名字。
type name=string; type nameFn=()=>string;function test(n:name|nameFn):name{if(typeof n=='string'){return n;}else{return n();} }
2.字符串字面量类型
用来约束取值只能是某几个字符串中的一个。
类型别名与字符串字面量类型都是使用 type 进行定义。
type EventNames='click'|'scroll'|'mousemove'; function handleEvent(el:Element,event:EventNames){} handleEvent(document.body,'scroll'); handleEvent(document.body,'dbclick');//error : Argument of type '"dbclick"' is not assignable to parameter of type 'EventNames'.
3.元组
数组合并了相同类型的对象,而元组(Tuple)合并了不同类型的对象。
let list:[string,number]=['aa',2];// 当直接对元组类型的变量进行初始化或者赋值的时候,需要提供所有元组类型中指定的项。let list1:[string,number]=['aa'];//error:Type '[string]' is not assignable to type '[string, number]'.
4.枚举
枚举(Enum)类型用于取值被限定在一定范围内的场景
// 枚举使用 enum 关键字来定义 // 枚举成员会被赋值为从 0 开始递增的数字,同时也会对枚举值到枚举名进行反向映射: enum color {red,green,blue}; console.log(color[0],color[1],color[2]);//red green blue console.log(color['red'],color['green'],color['blue']);//0 1 2// 1.手动赋值// 手动赋值的枚举项也可以为小数或负数,不是数字,此时后续未手动赋值的项的递增步长仍为 1 enum color {red=1.5,green,blue='a'};console.log(color['red'],color['green'],color['blue']);//1.5 2.5 "a"// 2. 常数项和计算所得项// 计算所得项 enum color {red,green,blue="blue".length}; console.log(color['red'],color['green'],color['blue']);//0 1 4// 如果紧接在计算所得项后面的是未手动赋值的项,那么它就会因为无法获得初始值而报错: // enum Color {Red = "red".length, Green, Blue};//error: Enum member must have initializer// 3.常数枚举 const // 不能包含计算成员 const enum color {red,green,blue}; console.log(color['red'],color['green'],color['blue']);//0 1 2// 4.外部枚举 // 使用 declare enum 定义的枚举类型 // 外部枚举与声明语句一样,常出现在声明文件中。 declare enum color {red,green,blue}; console.log(color['red'],color['green'],color['blue']);//0 1 2
5.类
// 1.public private 和 protected // public 修饰的属性或方法是公有的,可以在任何地方被访问到,默认所有的属性和方法都是 public 的 // private 修饰的属性或方法是私有的,不能在声明它的类的外部访问,在子类中也是不允许访问的 // protected 修饰的属性或方法是受保护的,它和 private 类似,区别是它在子类中也是允许被访问的// ++++++private++++++ class Animal{private name;public constructor(name){this.name=name;} }class Cat extends Animal{constructor(name){super(name);console.log(this.name);//error: Property 'name' is private and only accessible within class 'Animal'. } }// ++++++protected++++++ class Animal{protected name;public constructor(name){this.name=name;} }class Cat extends Animal{constructor(name){super(name);console.log(this.name);//可以在子类中访问 } } let a=new Cat('ass'); console.log(a.name);//error:外部不可以访问// 2.抽象类 // abstract 用于定义抽象类和其中的抽象方法。// 抽象类是不允许被实例化的: // 抽象类中的抽象方法必须被子类实现: abstract class Animal{public name;constructor(name){this.name=name;}public abstract say();//抽象类中的抽象方法必须被子类实现: } // 抽象类是不允许被实例化的: let a=new Animal('aa');//error: Cannot create an instance of the abstract class 'Animal'. class Cat extends Animal{say(){console.log(`${this.name}++++++`);} }let b=new Cat('suaa'); b.say();// 3.类的类型 class Animal {name: string;constructor(name: string) {this.name = name;}sayHi(): string {return `My name is ${this.name}`;} }let a: Animal = new Animal('Jack'); console.log(a.sayHi()); // My name is Jack
6.类与接口
//1. 类实现接口 //有时候不同类之间可以有一些共有的特性,这时候就可以把特性提取成接口(interfaces),用 implements 关键字来实现。 // 一个类可以实现多个接口: interface eat{food(); } interface go{run(); } class Person implements eat,go{food(){console.log('apple');}run(){console.log('fast');} }// 2.接口继承接口 interface go{run(); } interface eat extends go{food(); }class Person implements eat{food(){}run(){} }// 3.接口继承类 class Point{x:number;y:number; }interface Point3d extends Point{z:number; } let point3d: Point3d = {x: 1, y: 2, z: 3};
7.泛型
泛型是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候在指定类型
// 在函数名后添加了 <T>,其中 T 用来指代任意输入的类型,在后面的输入 value: T 和输出 Array<T> 中即可使用了 function test<T>(len:number,value:T):Array<T>{let res:T[]=[];for(let i=0;i<len;i++){res[i]=value;}return res; } console.log(test(3,'a+'));//["a+", "a+", "a+"]// 1.多个类型参数 // 定义泛型的时候,可以一次定义多个类型参数:function test<T,U>(arr:[T,U]):[U,T]{return [arr[1],arr[0]] } console.log(test([1,'a']));//["a", 1]// 2.泛型约束 // 可以对泛型进行约束,只允许这个函数传入那些包含 length 属性的变量 interface lengthWise{length:number; }function getLen<T extends lengthWise>(param:T):T{console.log(param.length);return param; } getLen(7);// error TS2345: Argument of type '7' is not assignable to parameter of type 'Lengthwise'. getLen('aaa');// 多个类型参数之间也可以互相约束: function test<T extends U,U>(target:T,source:U):T{for(let id in source){target[id]=(<T>source)[id];}return target; } let b=test({ a: 1, b: 2, c: 3, d: 4 }, { b: 10, d: 20 }); console.log(b);//{a: 1, b: 10, c: 3, d: 20}// 3.泛型接口 interface CreateArrayFunc<T> {(length: number, value: T): Array<T>; }let createArray: CreateArrayFunc<any>; createArray = function<T>(length: number, value: T): Array<T> {let result: T[] = [];for (let i = 0; i < length; i++) {result[i] = value;}return result; }createArray(3, 'x'); // ['x', 'x', 'x']// 4.泛型类 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; };// 5.泛型参数的默认类型function createArray<T = string>(length: number, value: T): Array<T> {let result: T[] = [];for (let i = 0; i < length; i++) {result[i] = value;}return result; }
8.声明合并
如果定义了两个相同名字的函数,接口或类,那么它们会合并成一个类型
// 1.函数的合并function reverse(x: number): number; function reverse(x: string): string; 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('');} }// 2. 接口的合并 // 接口的属性在合并时会简单的合并到一个接口中 // 合并的属性的类型必须是唯一的: interface test{name:string; } interface test{name:string;//类型需要一致 age:number; } // 等价于 interface test{name:string;age:number; } // 3.类的合并与接口合并一致