TypeScript泛型

摘要:在本教程中,您将学习有关TypeScript泛型的知识,泛型允许您将类型用作形式参数。

TypeScript泛型介绍

TypeScript泛型允许您编写可重用和通用的函数、接口形式。在本教程中,您将重点关注开发泛型函数。

通过一个简单的例子来解释TypeScript泛型会更容易。

假设您需要开发一个函数,该函数返回数组数字的随机数。

以下getRandomNumberElement()函数接受一个数字数组作为参数,并从数组中返回一个随机元素

function getRandomNumberElement(items: number[]): number {
    let randomIndex = Math.floor(Math.random() * items.length);
    return items[randomIndex];
}Code language: TypeScript (typescript)

要获取数组的随机元素,您需要

  • 首先找到随机索引。
  • 根据随机索引获取随机元素。

为了找到数组的随机索引,我们使用Math.random()(它返回 0 到 1 之间的随机数),乘以数组的长度,并对结果应用Math.floor()

以下显示了如何使用getRandomNumberElement()函数

let numbers = [1, 5, 7, 4, 2, 9];
console.log(getRandomNumberElement(numbers));Code language: TypeScript (typescript)

假设您需要从字符串数组中获取随机元素。这一次,您可能会想出一个新的函数

function getRandomStringElement(items: string[]): string {
    let randomIndex = Math.floor(Math.random() * items.length);
    return items[randomIndex];
}Code language: TypeScript (typescript)

getRandomStringElement()函数的逻辑与getRandomNumberElement()函数相同。

此示例显示了如何使用getRandomStringElement()函数

let colors = ['red', 'green', 'blue'];
console.log(getRandomStringElement(colors));Code language: TypeScript (typescript)

稍后您可能需要在对象数组中获取随机元素。每次您想要从新的数组类型中获取随机元素时创建一个新函数是不可扩展的。

使用任何类型

解决此问题的一种方法是将数组参数的类型设置为any[]。通过这样做,您需要编写一个适用于any类型数组的函数。

function getRandomAnyElement(items: any[]): any {
    let randomIndex = Math.floor(Math.random() * items.length);
    return items[randomIndex];
}Code language: TypeScript (typescript)

getRandomAnyElement()适用于any类型的数组,包括数字、字符串、对象等等

let numbers = [1, 5, 7, 4, 2, 9];
let colors = ['red', 'green', 'blue'];

console.log(getRandomAnyElement(numbers));
console.log(getRandomAnyElement(colors));Code language: TypeScript (typescript)

此选项工作正常,但有一个缺点:它不允许您强制执行返回元素的类型。换句话说,它不是类型安全的。

一个更好的解决方案是使用泛型来避免代码重复并保留类型。

TypeScript泛型来帮忙

以下显示了一个泛型函数,它从T类型数组中返回随机元素

function getRandomElement<T>(items: T[]): T {
    let randomIndex = Math.floor(Math.random() * items.length);
    return items[randomIndex];
}Code language: TypeScript (typescript)

此函数使用类型变量TT允许您捕获调用函数时提供的类型。此外,该函数使用T类型变量作为其返回类型。

getRandomElement()函数是泛型的,因为它可以处理任何数据类型,包括字符串、数字、对象……

按照惯例,我们使用字母T作为类型变量。但是,您可以自由使用其他字母,例如AB C,……

调用泛型函数

以下显示了如何将getRandomElement()与数字数组一起使用

let numbers = [1, 5, 7, 4, 2, 9];
let randomEle = getRandomElement<number>(numbers); 
console.log(randomEle);Code language: TypeScript (typescript)

此示例将number显式地作为T类型传递到getRandomElement()函数中。

在实践中,您将使用类型推断来获取参数。这意味着您让TypeScript编译器根据您传入的参数的类型自动设置T的值,例如

let numbers = [1, 5, 7, 4, 2, 9];
let randomEle = getRandomElement(numbers); 
console.log(randomEle);Code language: TypeScript (typescript)

在此示例中,我们没有将number类型显式传递给getRandomElement()。编译器会查看参数并将其类型设置为T

现在,getRandomElement()函数也是类型安全的。例如,如果您将返回值分配给字符串变量,您将收到错误

let numbers = [1, 5, 7, 4, 2, 9];
let returnElem: string;
returnElem = getRandomElement(numbers);  // compiler errorCode language: TypeScript (typescript)

具有多个类型的泛型函数

以下说明了如何使用两个类型变量UV开发泛型函数

function merge<U, V>(obj1: U, obj2: V) {
    return {
        ...obj1,
        ...obj2
    };
}Code language: JavaScript (javascript)

merge()函数合并类型为UV的两个对象。它将两个对象的属性合并到一个对象中。

类型推断将merge()函数的返回值推断为UV的交集类型,即U & V

以下说明了如何使用合并两个对象的merge()函数

let result = merge(
    { name: 'John' },
    { jobTitle: 'Frontend Developer' }
);

console.log(result);Code language: JavaScript (javascript)

输出

{ name: 'John', jobTitle: 'Frontend Developer' }Code language: CSS (css)

TypeScript泛型的优点

以下是TypeScript泛型的优点

  • 利用编译时类型检查。
  • 消除类型转换
  • 允许您实现泛型算法。

总结

  • 使用TypeScript泛型开发可重用、通用和类型安全的函数、接口和类。
本教程是否有帮助?