TypeScript - 泛型



泛型是 TypeScript 中一个强大的特性,它允许您编写可重用的代码,这些代码可以处理不同类型的数据。它们充当占位符,当您使用泛型代码时,可以用特定的数据类型填充这些占位符。这提高了代码的灵活性以及可维护性。

问题示例

在深入了解 TypeScript 泛型之前,让我们先了解一下需要应用泛型的问题示例。

让我们从下面的示例开始,您希望记录作为参数传递的变量的值。

示例

在下面的代码中,我们定义了 printVar() 函数,该函数将数字值作为参数并将其值记录到控制台。接下来,我们通过传递 10 作为参数来调用该函数。

function printVar(val: number) {
    console.log(val); // Prints the value of val
}
printVar(10); // Invokes the function with a number

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

function printVar(val) {
    console.log(val); // Prints the value of val
}
printVar(10); // Invokes the function with a number

输出

其输出如下所示:

10

现在,假设您希望扩展 printVar() 函数的使用案例,以打印其他类型变量(如字符串、布尔值等)的值。一种方法如下面的示例所示。

示例

在下面的代码中,printVar() 函数可以接受数字、字符串或布尔类型的参数。

function printVar(val: number | string | boolean) {
    console.log(val); // Prints the value of val
}
printVar(true); // Invokes the function with a boolean value

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

function printVar(val) {
    console.log(val); // Prints the value of val
}
printVar(true); // Invokes the function with a boolean value

输出

输出如下所示:

true

如果要打印数组或对象值怎么办?您需要扩展“val”参数的类型,这使得代码难以阅读。

另一种使用“any”数据类型参数的方法如下面的示例所示。

示例

在下面的代码中,“val”参数的类型为 any。因此,它可以接受任何类型的参数。

function printVar(val: any) {
    console.log(val); // Prints the value of val
}
printVar("Hello world!"); // Invokes the function with a boolean value

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

function printVar(val) {
    console.log(val); // Prints the value of val
}
printVar("Hello world!"); // Invokes the function with a boolean value

输出

其输出如下所示:

Hello world!

上面代码的问题在于,您在函数内部将无法引用数据类型。无论您将字符串、数字、布尔值、数组等作为函数参数传递,在函数中都将获得变量的“any”类型。

这里,泛型函数就派上用场了。

TypeScript 泛型

在 TypeScript 中,泛型是一个允许创建可重用组件(如函数、类、接口等)的概念。它创建了一个可以处理多种数据类型而不是单个数据类型的函数、类等。简而言之,它允许开发人员创建可以处理多种数据类型的程序,并且从长远来看是可扩展的。

语法

用户可以按照以下语法在 TypeScript 中使用泛型变量与函数。

function printVar<T>(val: T) {
    // execute the code
}
printVar(val);
  • 开发人员可以在函数名后使用尖括号(<>)中的类型变量。

  • 之后,您可以使用类型变量 T 作为参数的类型。

  • 这里,开发人员可以使用任何有效的标识符代替“T”。

  • 之后,您可以使用任何数据类型的调用函数,并且函数会自动捕获变量的数据类型。

示例

在下面的示例中,printVar() 函数是一个泛型函数,它将任何数据类型的作为参数,并打印它。

之后,我们使用数组、对象和布尔值调用了该函数。在输出中,用户可以观察到它在没有任何错误的情况下打印了不同类型变量的值。

function printVar<T>(val: T) { // T is a generic type
    console.log("data: ", val);
}
let arr = [1, 2, 3];
let obj = { name: "John", age: 25 };

printVar(arr); // Val is array
printVar(obj); // Val is Object
printVar(true); // Val is boolean

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

function printVar(val) {
    console.log("data: ", val);
}
let arr = [1, 2, 3];
let obj = { name: "John", age: 25 };
printVar(arr); // Val is array
printVar(obj); // Val is Object
printVar(true); // Val is boolean

输出

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

data:  [ 1, 2, 3 ]
data:  { name: 'John', age: 25 }
data:  true

示例

在此代码中,printVar() 函数是一个泛型函数,它获取作为参数传递的变量值的类型。在调用该函数时,我们传递了不同数据类型的值,用户可以在输出中观察到每个变量的类型。

function printVar<T>(val: T) { // T is a generic type
    console.log("data: ", typeof val);
}

printVar(2); // Val is number
printVar("Hello"); // Val is string
printVar(true); // Val is boolean

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

function printVar(val) {
    console.log("data: ", typeof val);
}
printVar(2); // Val is number
printVar("Hello"); // Val is string
printVar(true); // Val is boolean

输出

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

data:  number
data:  string
data:  boolean

示例

在下面的代码中,concatenate() 函数分别采用类型为 TU 的两个参数。它使用扩展运算符连接“first”和“second”参数的值。

接下来,我们调用该函数以连接两个字符串和数组。在输出中,我们可以看到 concatenate() 函数在没有任何错误的情况下执行,并在控制台中打印最终输出。

function concatenate<T, U>(first: T, second: U): T & U {
    return {...first, ...second};
}

// Example usage with strings
const resultString = concatenate("Hello, ", "world!");
console.log(resultString); // Output: Hello, world!

// Example usage with arrays
const resultArray = concatenate([1, 2, 3], [4, 5, 6]);
console.log(resultArray); // Output: [1, 2, 3, 4, 5, 6]

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

function concatenate(first, second) {
    return Object.assign(Object.assign({}, first), second);
}
// Example usage with strings
const resultString = concatenate("Hello, ", "world!");
console.log(resultString); // Output: Hello, world!
// Example usage with arrays
const resultArray = concatenate([1, 2, 3], [4, 5, 6]);
console.log(resultArray); // Output: [1, 2, 3, 4, 5, 6]

输出

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

{
  '0': 'w',
  '1': 'o',
  '2': 'r',
  '3': 'l',
  '4': 'd',
  '5': '!',
  '6': ' '
}
{ '0': 4, '1': 5, '2': 6 }

泛型的优势

以下是 TypeScript 中使用泛型的一些优势。

  • 类型安全:泛型强制执行类型一致性,通过在编译时捕获错误来减少运行时错误。

  • 代码可重用性:开发人员可以定义单个泛型函数、类或接口,这些函数、类或接口可以处理不同的数据类型。它减少了代码重复。

  • 提高可读性:通过使用泛型,开发人员可以编写更简洁、更易于阅读的代码。

  • 增强性能:您可以通过避免不必要的类型转换和检查来提高应用程序的性能,方法是使用泛型。

广告