TypeSript 泛型约束
1、什么是泛型约束?
泛型约束即是对泛型的类型进行约束控制。
2、为什么要使用泛型约束?
当使用泛型参数的属性或者方法时,就需要对泛型进行约束。如下代码所示:
function getLength<T>(arg: T): T {
// Error: T doesn't have .length
return arg.length;
}
在上述例子中,我们想访问arg的length属性,但是编译器并不能证明每种类型都有length属性,所以就报错了。
如果我们想要限制函数去处理任意带有.length属性的所有类型,只要保证传入的类型有这个属性,为此,我们需要列出对于T的约束要求。为此,我们定义一个接口来描述约束条件。创建一个包含.length属性的接口,使用这个接口和extends关键字实现约束:
interface LengthInterface {
length: number;
}
function getLength<T extends LengthInterface>(arg: T): T {
// Now we know it has a .length property, so no more error
return arg.length;
}
现在这个泛型函数被定义了约束,因此它不再是适用于任意类型:
getLength(3); // Error, number doesn't have a .length property
我们需要传入符合约束类型的值,必须包含必须的属性:
getLength({length: 10, value: 3});
3、如何实现泛型约束?
实现泛型约束,有两种方式:
(1)指定接口类型,如上例所示。
(2)限制为某一类型,如下所示,类型参数T被限制成object类型:
function getKeys<T extends object>(data:T) :string[] {
const keys:Array<string> = Object.keys(data)
return keys
}
上面的 getKeys 方法用于获取一个对象的所有属性名,由于Object.keys是object的原型方法,所以要求data也必须是一个object类型。
4、在泛型约束中使用泛型
我们可以声明一个泛型参数,且它被另一个泛型参数所约束。比如,现在我们想要用属性名从对象里获取这个属性,并且我们想要确保这个属性存在于对象obj上,因此我们需要在这两个泛型之间使用约束:
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"); // 正确
getProperty(x, "m"); // 错误: m并不属于x的属性('a' | 'b' | 'c' | 'd')