TypeScript - 泛型约束



在 TypeScript 中,泛型约束允许你指定对可与泛型类型参数一起使用的类型的限制。这通过确保泛型代码仅适用于兼容的数据类型来增加一层类型安全。

问题示例

在深入研究泛型约束之前,让我们了解需要应用泛型约束的问题示例。

示例

在下面的代码中,我们创建了merge()泛型函数,它将两个对象作为参数,使用扩展运算符合并它们,并返回合并后的对象。

之后,我们通过传递两个对象作为参数来调用merge()函数,它成功地打印了合并后的对象。

// Generic function to merge two objects
function merge<T, U>(obj1: T, obj2: U) {
    return {...obj1, ...obj2};
}

// Invoke the function
const mergedObj = merge({name: 'Sam'}, {age: 30});
console.log(mergedObj); // Output: {name: 'Sam', age: 30}  

编译后,它将生成以下 JavaScript 代码。

// Generic function to merge two objects
function merge(obj1, obj2) {
    return Object.assign(Object.assign({}, obj1), obj2);
}
// Invoke the function
const mergedObj = merge({ name: 'Sam' }, { age: 30 });
console.log(mergedObj); // Output: {name: 'Sam', age: 30}  

输出

上面示例代码的输出如下:

{name: 'Sam', age: 30}

merge()函数具有泛型参数。因此,它可以接受任何数据类型的数值作为参数,包括对象。如果你传递布尔值作为第二个参数会怎样?让我们看看下面的例子。

示例

下面的示例代码与之前的代码非常相似。我们只是在调用时将merge()函数的第二个参数更改为布尔值。

// Generic function to merge two objects
function merge<T, U>(obj1: T, obj2: U) {
    return {...obj1, ...obj2};
}

// Invoke the function
const mergedObj = merge({name: 'Sam'}, true);
console.log(mergedObj); // Output: {name: 'Sam'}  

编译后,它将生成以下 JavaScript 代码。

// Generic function to merge two objects
function merge(obj1, obj2) {
    return Object.assign(Object.assign({}, obj1), obj2);
}
// Invoke the function
const mergedObj = merge({ name: 'Sam' }, true);
console.log(mergedObj); // Output: {name: 'Sam'}  

输出

上面示例代码的输出如下:

{name: 'Sam'}

上面的代码只打印第一个对象,因为第二个参数是布尔值而不是对象。为了解决上面示例代码中发现的问题,开发人员可以使用泛型约束。

TypeScript 中泛型约束的工作原理?

泛型约束允许我们将泛型参数限制为仅接受特定类型的数值。即你可以缩小泛型参数的类型。

语法

您可以按照以下语法使用泛型参数的泛型约束。

function merge<T extends object>(obj1: T) {
    // Code to execute
}
  • 在上面的语法中,“T”是一个泛型类型,“extends”是一个关键字,“object”是一个数据类型。

  • 在这里,“T”只接受具有“object”数据类型的数值。

让我们通过下面的例子来更多地了解泛型约束。现在,如果你尝试编译下面的代码,你将得到编译错误,因为泛型参数只能接受对象参数,但我们传递的是布尔值。

// Generic function to merge two objects
function merge<T extends object, U extends object>(obj1: T, obj2: U) {
    return { ...obj1, ...obj2 };
}

// Invoke the function
const mergedObj = merge({ name: 'Sam' }, true);
console.log(mergedObj);

编译上面的 TypeScript 代码时,编译器会显示以下错误:

Argument of type 'boolean' is not assignable to parameter of type 'object'.

这样,我们可以限制泛型参数以接受特定数据类型的数值。

示例(使用接口扩展泛型类型)

让我们逐步了解下面的代码。

  • 我们定义了包含 name、age 和 email 属性的“Person”接口。

  • 接下来,我们定义了包含“empCode”和“empDept”属性的“Employee”接口。

  • merge()函数包含两个泛型参数 T(Person 类型)和 U(Employee 类型)。

  • merge()函数中,我们合并两个对象。

  • 之后,我们分别定义了两个 Person 和 Employee 类型的对象。

  • 接下来,我们通过传递对象作为参数来调用merge()函数,代码运行没有任何错误。

// Define Person interface
interface Person {
    name: string;
    age: number;
    email: string;
}

// Define Employee interface
interface Employee {
    empCode: number;
    empDept: string;
}

// Generic function which takes Objects of the Person and Employee interfaces types
function merge<T extends Person, U extends Employee>(obj1: T, obj2: U) {
    return { ...obj1, ...obj2 };
}

// Create two objects
const person: Person = { name: 'John', age: 30, email: '[email protected]' };
const employee: Employee = { empCode: 1001, empDept: 'IT' };

// Invoke the function
const mergedObj = merge(person, employee);
console.log(mergedObj);

编译后,它将生成以下 JavaScript 代码。

// Generic function which takes Objects of the Person and Employee interfaces types
function merge(obj1, obj2) {
    return Object.assign(Object.assign({}, obj1), obj2);
}
// Create two objects
const person = { name: 'John', age: 30, email: '[email protected]' };
const employee = { empCode: 1001, empDept: 'IT' };
// Invoke the function
const mergedObj = merge(person, employee);
console.log(mergedObj);

输出

上面示例代码的输出如下:

{
  name: 'John',
  age: 30,
  email: '[email protected]',
  empCode: 1001,
  empDept: 'IT'
}

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

TypeScript 还允许你定义一个类型参数,该参数受同一函数的另一个参数约束。

让我们通过下面的例子来了解它。

示例

在下面的代码中,类型“U”扩展了在第一个参数中接收的对象的键。因此,它将接受obj对象的键作为参数,以避免函数体中的错误。

接下来,我们通过传递“obj”对象作为参数来调用getValue()函数。它在输出中打印键值。

// Parameter U ensures that the key is a valid key of the object T.
function getValue<T extends object, U extends keyof T>(obj: T, key: U) {
    return obj[key];
}

// Define an object
const obj = {
    name: 'Sam',
    age: 34
};

// Get the value of the key 'name'
const name1 = getValue(obj, 'name');
console.log(name1); // Sam

编译后,它将生成以下 JavaScript 代码。

// Parameter U ensures that the key is a valid key of the object T.
function getValue(obj, key) {
    return obj[key];
}
// Define an object
const obj = {
    name: 'Sam',
    age: 34
};
// Get the value of the key 'name'
const name1 = getValue(obj, 'name');
console.log(name1); // Sam

输出

上面示例代码的输出如下:

Sam

我们了解到泛型约束对于接受特定数据类型的数值作为参数而不是接受所有数据类型的数值很有用。

广告