TypeScript 泛型学习指南

泛型是TypeScript中非常重要的概念,它允许我们创建可重用的组件,这些组件可以支持多种类型而不只是一个单一类型。

# 1. 基本泛型示例

# 泛型函数

// 普通函数只能返回一种特定类型
function identity(arg: number): number {
    return arg;
}

// 使用泛型,可以适用于多种类型
function identityGeneric<T>(arg: T): T {
    return arg;
}

// 使用
let output1 = identityGeneric<string>("myString");  // 类型为string
let output2 = identityGeneric<number>(100);        // 类型为number
1
2
3
4
5
6
7
8
9
10
11
12
13

# 泛型自动类型推断

// TypeScript可以自动推断泛型类型
let output3 = identityGeneric("myString");  // 类型推断为string
let output4 = identityGeneric(100);         // 类型推断为number
1
2
3

# 2. 泛型数组示例

// 处理数组的泛型函数
function loggingIdentity<T>(arg: T[]): T[] {
    console.log(arg.length);  // 数组有length属性
    return arg;
}

// 或者可以这样写
function loggingIdentity2<T>(arg: Array<T>): Array<T> {
    console.log(arg.length);
    return arg;
}

// 使用
let arr1 = loggingIdentity([1, 2, 3]);       // T被推断为number
let arr2 = loggingIdentity(["a", "b", "c"]); // T被推断为string
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 3. 泛型接口

// 定义泛型接口
interface GenericIdentityFn<T> {
    (arg: T): T;
}

// 使用
function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;
1
2
3
4
5
6
7
8
9
10
11

# 4. 泛型类

class GenericNumber<T> {
    zeroValue: T;
    add: (x: T, y: T) => T;
}

// 使用number类型
let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = (x, y) => x + y;

// 使用string类型
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = (x, y) => x + y;

console.log(stringNumeric.add("Hello ", "World")); // 输出 "Hello World"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 5. 泛型约束

有时候我们需要限制泛型的类型范围。

interface Lengthwise {
    length: number;
}

// 使用extends约束泛型T必须包含length属性
function loggingIdentityWithConstraint<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);
    return arg;
}

// 正确使用
loggingIdentityWithConstraint({length: 10, value: 3});
loggingIdentityWithConstraint("hello"); // string有length属性

// 错误使用
// loggingIdentityWithConstraint(3); // 数字没有length属性
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

# 6. 在泛型约束中使用类型参数

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

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a"); // 正确
// getProperty(x, "m"); // 错误: 'm'不在x的key中
1
2
3
4
5
6
7
8

# 7. 泛型与默认类型

interface MyGenericInterface<T = string> {
    value: T;
}

// 不指定类型参数,使用默认string
let obj1: MyGenericInterface = { value: "hello" };

// 明确指定类型
let obj2: MyGenericInterface<number> = { value: 123 };
1
2
3
4
5
6
7
8
9

# 8. 实用示例:数据响应包装

interface ApiResponse<T> {
    success: boolean;
    data?: T;
    error?: string;
}

function fetchUser(): ApiResponse<{name: string, age: number}> {
    // 模拟API调用
    return {
        success: true,
        data: {name: "Alice", age: 30}
    };
}

function fetchProducts(): ApiResponse<Array<{id: number, name: string, price: number}>> {
    // 模拟API调用
    return {
        success: true,
        data: [
            {id: 1, name: "Laptop", price: 999},
            {id: 2, name: "Phone", price: 699}
        ]
    };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

通过这些例子,你应该对TypeScript泛型有了基本的理解。泛型的主要优势是:

  1. 提高代码复用性
  2. 提供更好的类型检查
  3. 减少使用any类型,保持类型安全