泛型
主要用于创建重用组件,允许用户去使用自己的类型去重用这些组件。
如何定义泛型?
function identity<T>(arg: T): T {
return arg;
}
对比一下
function identity(arg: any): any {
return arg;
}
就很容易理解了,实际上就是运用了一个变量T去捕捉用户提供的类型 (例如: number, string),然后再使用T作为返回值类型。那为什么要使用泛型而不使用any. 主要是为了保证输入输出的类型都一致。比如下面这个例子,明确指出传入的参数类型是number,返回值类型是number.
function identity(arg: number): number {
return arg;
}
如何使用泛型?
两种方式:
1.明确设置T的值
2.编译器根据传入的参数类型自动设置T的值
function identify<T>(arg: T) {
return arg;
}
let output1 = identify<string>('my String'); //方式一
let output2 = identify('my String'); //方式二
泛型接口
interface GenericIdentityFn<T> {
(arg: T): T
}
function identity<T>(arg: T): T{
return arg
}
let myIdentity: GenericIdentityFn<number> = identity;
myIdentity('string')// error
myIdentity(123) //correct
泛型类
class GenericNumber<T> {
zeroValue: T;
add: (x: T, y: T) => T;
}
//定义成number类型
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function(x, y) { return x + y; };
console.log(myGenericNumber.add(myGenericNumber.zeroValue, 2));
//定义成string类型
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };
console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));
泛型里面调用通用属性
function loggingIdentity<T>(arg: T): T {
console.log(arg.length); // Error: T doesn't have .length
return arg;
}
上面这个例子原意是想设置一个通用函数,但是呢,翻译器无法确定每种类型都具有.length属性。所以它不高兴,让你不要做这种假设。
那么如何解决呢?
第一种方式把 T设置成数组,告诉编译器传进来的类型具有.length方法,不需要担心
function loggingIdentity<T>(arg: T[]): T[] {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
或
function loggingIdentity<T>(arg: Array<T>): Array<T> {
console.log(arg.length); // Array has a .length, so no more error
return arg;
}
第二种
具有length属性的除了数组,字符串也有嘛。光是上一种方法不能最大化我们的需求。就只有寻求第二种方式“给T设置约束”
设置一个接口给T继承,明示翻译器。限制了传进来的参数都是具有length属性的。不然就会报错. (官方称之为”通用约束”)
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
loggingIdentity(123); // error!!!
loggingIdentity({length: 10, value: 3});
loggingIdentity([1,2,3]);
loggingIdentity('string');
通用约束中使用变量参数
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // okay
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
用泛型写工厂类型
function create<T>(c: {new(): T; }): T {
return new c();
}
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
constructor(){
super();
this.keeper = new BeeKeeper();
}
}
class Lion extends Animal {
keeper: ZooKeeper;
constructor(){
super();
this.keeper = new ZooKeeper();
}
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!