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')

原文链接:http://www.mybatis.cn/typescript/2020.html

标签: none

添加新评论