Skip to content

TypeScript Generic Constraints

摘要:在本教程中,你将学习 TypeScript 中的泛型约束。

TypeScript 中泛型约束的介绍

考虑以下示例:

ts
function merge<U, V>(obj1: U, obj2: V) {
    return {
        ...obj1,
        ...obj2
    };
}

merge() 函数是一个可以合并两个对象的范型函数。例如:

ts
let person = merge(
    { name: 'John' },
    { age: 25 }
);

console.log(result);

输出:

ts
{ name: 'John', age: 25 }

它完美地工作。

merge() 函数需要两个对象。但是,它不会阻止你像这样传递非对象

ts
let person = merge(
    { name: 'John' },
    25
);

console.log(person);

输出:

ts
{ name: 'John' }

TypeScript 并没有发出任何错误。

你可能想给 merge() 函数添加一个约束,而不是对所有的类型进行工作,这样它就只能对对象进行工作。

要做到这一点,你需要列出需求,作为 UV 类型可以是什么的约束条件。

为了表示这个约束,你使用 extends 关键字。比如说:

ts
function merge<U extends object, V extends object>(obj1: U, obj2: V) {
    return {
        ...obj1,
        ...obj2
    };
}

因为 merge() 函数现在被约束了,它将不再对所有类型工作。相反,它只对对象类型起作用。

下面的情况将导致一个错误:

ts
let person = merge(
    { name: 'John' },
    25
);

Error:

ts
Argument of type '25' is not assignable to parameter of type 'object'.

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

TypeScript 允许你声明一个由另一个类型参数约束的类型参数

以下 prop() 函数接受一个对象和一个属性名称。它返回属性的值:

ts
function prop<T, K>(obj: T, key: K) {
    return obj[key];
}

编译器会发出以下错误:

ts
Type 'K' cannot be used to index type 'T'.

为了解决这个错误,你需要添加一个约束条件到 K 上,以确保它是 T 的 key,如下所示:

ts
function prop<T, K extends keyof T>(obj: T, key: K) {
    return obj[key];
}

如果你给 prop 函数传递一个 obj 上存在的属性名,编译器不会报错。比如说:

ts
let str = prop({ name: 'John' }, 'name');
console.log(str);

输出:

ts
John

然而,如果你传递一个不存在于第一个参数上的属性名,则编译器会发出错误:

ts
let str = prop({ name: 'John' }, 'age');

Error:

ts
Argument of type '"age"' is not assignable to parameter of type '"name"'.

总结

  • 使用 extends 关键字将类型参数约束为特定类型。
  • 使用 extends keyof 来约束作为另一对象属性的类型。