TypeScript中的泛型

TypeScript中的泛型

本文将解释TypeScript中的泛型。

YouTube Video

TypeScript中的泛型

TypeScript中的泛型是一项功能,通过参数化类型,可以定义可重用且类型安全的函数、类和接口。使用泛型可以编写不依赖特定类型的代码,从而可以对各种类型执行相同的操作。

泛型基础

泛型类似于模板,可以接受类型作为参数,使函数和类能够处理不同的类型。

泛型函数

以下是一个使用泛型指定参数类型的函数示例。

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity<number>(42));       // 42
6console.log(identity<string>("Hello"));  // Hello
  • T 是一个泛型类型参数,表示函数参数和返回值的类型。实际的类型在调用函数时确定。
  • 通过显式指定 <number><string>,您正在指定类型。

泛型类型在没有显式指定的情况下也能工作,因为TypeScript会进行类型推断。

1function identity<T>(value: T): T {
2    return value;
3}
4
5console.log(identity(42));       // 42
6console.log(identity("Hello"));  // Hello
  • 即使没有明确指定 <number><string>,类型推断也会发生。identity(42) 被推断为 number,而 identity("Hello") 被推断为 string

泛型约束

通过对泛型设置约束,可以将其限制为只接受特定的类型。

1function loggingIdentity<T extends { length: number }>(arg: T): T {
2    console.log(arg.length);
3    return arg;
4}
5
6loggingIdentity("Hello");  // 5
7loggingIdentity([1, 2, 3]);  // 3
8
9// loggingIdentity(42);  // Error: number does not have a length property.
  • 指定 T extends { length: number } 表示 T 必须是具有 length 属性的类型。因此,缺少 length 属性的类型将不会被接受。

keyof 的结合使用

将泛型与 keyof 结合使用,可以以类型安全的方式获取属性名。

1function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
2  return obj[key];
3}
4
5const person = { name: "Bob", age: 30 };
6const personName = getProperty(person, "name"); // string
7console.log(personName);
8
9// const error = getProperty(person, "unknown"); // Error
  • Kkeyof T 的约束,表示只能指定 T 中存在的键。指定不存在的键会导致编译错误。

泛型类

类也可以使用泛型定义。泛型类为属性和方法提供灵活的类型。

 1class Box<T> {
 2    private _value: T;
 3
 4    constructor(value: T) {
 5        this._value = value;
 6    }
 7
 8    public getValue(): T {
 9        return this._value;
10    }
11
12    public setValue(value: T): void {
13        this._value = value;
14    }
15}
16
17const numberBox = new Box<number>(100);
18console.log(numberBox.getValue());  // 100
19
20const stringBox = new Box<string>("Hello");
21console.log(stringBox.getValue());  // Hello
  • Box<T> 将类中使用的类型 T 声明为泛型。这样可以将同一个类重用于不同的类型。

泛型接口

泛型也可以与接口一起使用。

 1interface Pair<T, U> {
 2    first: T;
 3    second: U;
 4}
 5
 6const numberStringPair: Pair<number, string> = { first: 1, second: "One" };
 7console.log(numberStringPair);  // { first: 1, second: 'One' }
 8
 9const booleanArrayPair: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };
10console.log(booleanArrayPair);  // { first: true, second: [ 1, 2, 3 ] }
  • 通过使用 Pair<T, U> 指定两个泛型类型,可以定义具有不同类型组合的对象。

默认类型参数

还可以为泛型类型参数指定默认类型。

1function createArray<T = string>(length: number, value: T): T[] {
2    return Array(length).fill(value);
3}
4
5console.log(createArray(3, "a"));   // ['a', 'a', 'a']
6console.log(createArray(3, 100));   // [100, 100, 100]
  • 我们通过使用 <T = string> 将默认类型参数设置为 string。如果没有显式指定类型,T 将默认为 string 类型。

泛型类型别名

泛型也可以用作类型别名 (type)。

 1type Result<T> = {
 2    success: boolean;
 3    data: T;
 4};
 5
 6const successResult: Result<number> = { success: true, data: 42 };
 7const errorResult: Result<string> = { success: false, data: "Error occurred" };
 8
 9console.log(successResult);  // { success: true, data: 42 }
10console.log(errorResult);    // { success: false, data: 'Error occurred' }
  • Result<T> 表示一个包含类型为 T 的数据的结果对象。通过这种方式,可以使用泛型创建灵活的类型别名。

多种泛型类型

通过使用多种泛型类型,可以定义更加通用的函数和类。

1function merge<T, U>(obj1: T, obj2: U): T & U {
2    return { ...obj1, ...obj2 };
3}
4
5const person = { name: "Alice" };
6const job = { title: "Engineer" };
7
8const merged = merge(person, job);
9console.log(merged);  // { name: 'Alice', title: 'Engineer' }
  • merge 函数接收两种不同类型 TU,然后将它们组合并返回一个新对象。

总结

  • 泛型 通过将类型作为参数,使代码可复用且类型安全。
  • 通过在 函数、类和接口 中使用泛型,可以编写可以处理各种类型的灵活逻辑。
  • 通过向类型参数添加 约束 或设置 默认类型参数,可以控制泛型的范围。

通过使用泛型,你可以编写与类型无关的通用代码,充分利用 TypeScript 强大的类型系统。

您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。

YouTube Video