yaoningvital / blog

my blog
31 stars 4 forks source link

TypeScript -- Generic Constraints 泛型约束 #187

Open yaoningvital opened 4 years ago

yaoningvital commented 4 years ago

原文地址:http://www.typescriptlang.org/docs/handbook/generics.html

泛型约束

在下面这个泛型函数中,因为不确定参数 arg 一定会有 length 属性,所以Ts 报错:

function loggingIdentity<T>(arg: T): T{
    console.log(arg.length)  // Error TS2339: Property 'length' does not exist on type 'T'.
    return arg;
}

可以给T设置一些限制,使它具备 length 属性,通过创建一个描述约束的接口来实现:

interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T{
    console.log(arg.length)
    return arg;
}

因为现在泛型函数 loggingIdentity 受到了限制,它不能再接收任何类型的参数,所以下面的调用会报错:

loggingIdentity(3) // TS2345: Argument of type '3' is not assignable to parameter of type 'Lengthwise'.

我们只能传一些具有约束中指明的属性的值到 loggingIdentity ,才能通过 Ts 编译器的检查。

loggingIdentity({ size:10, length:20})
loggingIdentity('hello')

在泛型约束中使用“类型参数”

参数类型变量 可以受其他参数类型变量 的约束。比如:

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") // Error TS2345: Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.

image

1、上面的代码中,设定泛型函数 getProperty 的参数 obj的类型为变量 T表示的类型,参数 key 的类型为 变量 K表示的类型。 2、 K extends keyof T 表示 K 应该是T的键值。 3、"a"是x的一个键值,所以 getProperty(x, "a")调用是OK的。 4、"m"不是 x 的一个键值,所以 getProperty(x,"m") 调用会报错。

在泛型中使用类类型

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

1、上面的代码中,c 表示一个构造函数,create 返回一个实例,所以 T 表示 一个实例,是一个表示实例的变量。 2、create 函数的参数 c 的类型是一个构造函数,用来描述这个构造函数的泛型函数是: {new (): T;},也可以表示为: new () => T

总结,下面两种写法都可以: 方式一:

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

方式二:

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

如下图所示: image