- 泛型函数
- 泛型类
一、泛型函数
在泛型函数之前,先简单的描述一下泛型,将变量定义成泛型可以在使用变量时来决定它的类型。什么意思呢?假如现在有一个函数,可能出现参数和返回值出现多种情况的现象,只有在调用函数受参数时才能确定它们的类型,就可以将函数定义成一个泛型函数,然后在调用这个函数的时候设定参数和返回值的类型。
1 function identity<T>(arg: T): T { 2 return arg; 3 } 4 console.log(identity<number[]>([1,2,3]));//[1,2,3] 5 console.log(identity<string>('aaa'));//aaa
泛型相关的内容相对比较简单,官方文档也是非常的详细,这里就不做太多分析,就针对各种基本应用展示一些示例:
1 //可以这样写(参数和返回值使用泛型类型的数组类型) 2 function fun<T>(arg: T[]):T[]{ 3 console.log(arg.length); 4 return arg; 5 } 6 //还可以这样这(参数使用泛型类型,返回值使用泛型类型的数组类型) 7 function fun1<T>(arg: T):T[]{ 8 return []; 9 } 10 //但是,不能这样写 11 // function fun2<T>(arg: T[]):T{ 12 // return arg.length; 13 // }
也可以将泛型函数作为泛型函数类型使用:
1 function identity<T>(arg: T): T{ 2 return arg; 3 } 4 let myIdentity: <U>(arg: U) => U = identity;
由上面的泛型函数类型应该就很容易想到,可不可以定义一个泛型接口?这当然是没有问题的:
1 //定义泛型函数接口 2 interface GenericIdentityFn<T> { 3 (arg: T): T; 4 } 5 interface GenericIdentityFn<T> { 6 (arg: T): T; 7 } 8 //这里个泛型方法可以直接写成泛型函数接口的实现 9 //这里将它作为泛型函数类型 10 //用这个泛型函数类型的一个函数变量作为泛型函数接口的实现 11 function identity<T>(arg: T): T{ 12 return arg; 13 } 14 //实现泛型函数接口 15 let myGenericIdentityfn : GenericIdentityFn<string | number | number[]> = identity; 16 identity('str');
然后,上面注释中还有一点忘了,实现泛型接口时可以给泛型传递多个类型,然后用或(|)运算符连接。
二、泛型类
泛型类与泛型函数非常类似,没有太多可说的,直接上代码,官方文档中的第一个示例只写了一个抽象像或者接口一样的class内容,所以要想正确的测试,需要补全代码,下面就是我补全的代码:
1 class GenericNumber<T> { 2 zeroValue: T; 3 constructor(zero:T){ 4 this.zeroValue = zero; 5 } 6 add(x: T, y: T):T[]{ 7 return [x,y]; 8 } 9 } 10 11 let myGenericNumber = new GenericNumber<number>(0); 12 myGenericNumber.zeroValue = 100; 13 myGenericNumber.add(10,100);
可用使用泛型类接口的方式来解决在泛型函数中无法描述内部一些数据类型的问题,也是在官方的文档中给出了示例代码:
1 interface Lengthwise { 2 length: number; 3 } 4 5 function loggingIdentity<T extends Lengthwise>(arg: T): T { 6 console.log(arg.length); // Now we know it has a .length property, so no more error 7 return arg; 8 } 9 console.log( loggingIdentity({length:10,value:3}) );
泛型类接口也被叫做泛型约束,简单的说就是定一个类类型接口,然后创建泛型方法或者类型的时候继承这个接口,然后再调用函数或者实例化类的时候根据类型类型接口,传入对应的类型值作为泛型的类型:
1 interface G{ 2 objG:object; 3 keyG:string; 4 } 5 function getProperty<T extends G>(obj:T['objG'], key:T['keyG']){ 6 //return obj[key] -- 由于key是不确定的是没办法推断它的类型,所以没法被实现 7 return obj 8 } 9 10 let x = { a: 1, b: 2, c: 3, d: 4 }; 11 12 console.log( getProperty(x, "a")); // { a: 1, b: 2, c: 3, d: 4 }
在泛型里使用类型:简单的说就是泛型的类型是由指定class,所以被这个类型指定的参数或者返回值就是该类的实例化对象。
1 //注意这个官方示例类定义时没有给成员变量初始化赋值,也没有实现构造赋值,所以所有类中的成员都会报错 2 class BeeKeeper { 3 hasMask: boolean; 4 } 5 class ZooKeeper { 6 nametag: string; 7 } 8 class Animal { 9 numLegs: number; 10 } 11 class Bee extends Animal { 12 keeper: BeeKeeper; 13 } 14 class Lion extends Animal { 15 keeper: ZooKeeper; 16 } 17 function createInstance<A extends Animal>(c: new () => A): A { 18 return new c(); 19 } 20 createInstance(Lion).keeper.nametag; // typechecks! 21 createInstance(Bee).keeper.hasMask; // typechecks!