TypeScript-2
二、进阶
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.类的合并与接口合并一致