TypeScript泛型约束

泛型约束

有了泛型之后,一个函数或容器类能处理的类型一下子扩到了无限大,似乎有点失控的感觉。所以这里又产生了一个约束的概念。我们可以声明对类型参数进行约束。

我们还拿上文中的student栗子来说,想访问value的length属性,但是编译器并不能证明每种类型都有length属性,所以就报错了。

student = <T extends {}>(value: T): T => {
	//Property 'length' does not exist on type 'T'.ts(2339)
    console.log(value.length);
    return value;
}

相比于操作any所有类型,我们想要限制函数去处理任意带有.length属性的所有类型。 只要传入的类型有这个属性,我们就允许,就是说至少包含这一属性。 为此,我们需要列出对于T的约束要求。为此,我们定义一个接口来描述约束条件。 创建一个包含 .length属性的接口,使用这个接口和extends关键字来实现约束:

interface LengthDefine {
    length: number;
}
//这样函数定义是编译器就不会报错了
student = <T extends LengthDefine>(value: T): T => {
    console.log(value.length);
    return value;
}

调用:

传入的是字符串能,里面含有length属性,能正常运行

let name: string = this.student<string>(itemFun.getName('Jack'));

如果传入的是number类型的数字:

let age = this.student(10);
//Argument of type '10' is not assignable to parameter of type 'LengthDefine'.

我们需要传入符合约束类型的值,必须包含必须的属性:

let name: string = this.student<string>('Jack');
let age = this.student({length: 1, value: 10});
age的类型推导结果:
(property) Init.student: <{
    length: number;
    value: number;
}>(value: {
    length: number;
    value: number;
}) => {
    length: number;
    value: number;
}

约束为类型参数

我们可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束。

getProperty = <T, K extends keyof T>(obj: T, key: K) => {
    return obj[key]
}
let obj = {a:1, b:"2", c:3};
console.log(this.getProperty(obj, 'a'));
//1
console.log(this.getProperty(obj, 'd'));
//Argument of type '"d"' is not assignable to parameter of type '"a" | "b" | "c"'.ts(2345)

约束为类类型

在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型。比如:

function create<T> (c: {new(): T;}): T {
    return new c();
}

使用原型属性推断并约束构造函数与类实例的关系

class Keeper1 {
    hasMask: boolean;
}

class Keeper2 {
    nameTag: string;
}

class Keeper3 {
    numLength: number;
}

class ChildrenKeeper1 extends Keeper3 {
    keeper: Keeper1;
}


class ChildrenKeeper2 extends Keeper3 {
    keeper: Keeper2;
}

function createInstance<A extends Keeper3> (c: new() => A): A {
    return new c();
}

console.log(createInstance(ChildrenKeeper1));
//ChildrenKeeper1 {}
console.log(createInstance(ChildrenKeeper2));
//ChildrenKeeper2 {}
参与评论 您还未登录,请先 登录 后发表或查看评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:黑客帝国 设计师:我叫白小胖 返回首页

打赏作者

浅夏晴空

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值