目录

  1. 泛型概述
  2. 为什么使用泛型
  3. 基本语法
  4. 泛型函数
  5. 泛型接口
  6. 泛型类
  7. 泛型约束
  8. 泛型工具类型
  9. 泛型高级用法
  10. 最佳实践
  11. 参考资料

1. 泛型概述

泛型(Generics)是 TypeScript 提供的一种**类型参数化(Type Parameterization)**机制,允许在定义时不指定具体类型,而在使用时再传入具体类型。

示例:

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

console.log(identity<string>("Hello")); // "Hello"
console.log(identity<number>(123)); // 123

T 是一个泛型类型变量,它在调用 identity 时被替换为具体类型。


2. 为什么使用泛型

  • 提升代码复用性:让代码支持不同类型,避免重复代码。
  • 增强类型安全性:在编译期检查类型,避免运行时错误。
  • 提高可读性和维护性:通过约束类型关系,提高代码的可理解性。

泛型 vs. any

  • any 失去了类型安全function identityAny(arg: any): any { return arg; } identityAny("Hello") 可能返回 任意类型,无法保证输入输出类型一致。
  • 泛型保持类型信息function identity<T>(arg: T): T { return arg; } identity<string>("Hello") 返回值类型就是 string,不会变成 any

3. 基本语法

泛型的基本语法:

function functionName<T>(arg: T): T {
    return arg;
}

  • T 是一个类型变量,表示任意类型。
  • 在调用函数时,可以通过 <T> 传入具体类型: let output = functionName<number>(10); // 指定 T 为 number

4. 泛型函数

(1)泛型函数的定义

function reverseArray<T>(items: T[]): T[] {
    return items.reverse();
}

console.log(reverseArray<number>([1, 2, 3])); // [3, 2, 1]
console.log(reverseArray<string>(["a", "b", "c"])); // ["c", "b", "a"]

(2)类型推导

TypeScript 可以自动推导泛型类型:

const numbers = reverseArray([1, 2, 3]); // TypeScript 推断 T 为 number


5. 泛型接口

(1)定义泛型接口

interface Pair<T, U> {
    first: T;
    second: U;
}

const p1: Pair<number, string> = { first: 1, second: "hello" };
const p2: Pair<boolean, number[]> = { first: true, second: [1, 2, 3] };

(2)泛型函数 + 泛型接口

interface Repository<T> {
    data: T[];
    add: (item: T) => void;
    getAll: () => T[];
}

class UserRepo implements Repository<string> {
    data: string[] = [];
    add(item: string) { this.data.push(item); }
    getAll() { return this.data; }
}

const users = new UserRepo();
users.add("Alice");
console.log(users.getAll()); // ["Alice"]


6. 泛型类

(1)基本用法

class Box<T> {
    private value: T;
    
    constructor(value: T) {
        this.value = value;
    }

    getValue(): T {
        return this.value;
    }
}

const numberBox = new Box<number>(100);
console.log(numberBox.getValue()); // 100

(2)泛型约束

class KeyValuePair<K, V> {
    constructor(public key: K, public value: V) {}
}

const pair = new KeyValuePair<string, number>("age", 25);
console.log(pair.key, pair.value); // "age" 25


7. 泛型约束

(1)约束为特定类型

function printLength<T extends { length: number }>(arg: T): void {
    console.log(arg.length);
}

printLength("Hello"); // 5
printLength([1, 2, 3]); // 3

(2)约束为类

class Animal { name: string = ""; }
class Dog extends Animal { breed: string = ""; }

function createInstance<T extends Animal>(Ctor: new () => T): T {
    return new Ctor();
}

const dog = createInstance(Dog);
console.log(dog instanceof Dog); // true


8. 泛型工具类型

TypeScript 提供了一些内置的泛型工具类型,如:

  • Partial<T>:将对象的所有属性变为可选
  • Readonly<T>:将对象的所有属性变为只读
  • Record<K, T>:创建键值对类型
  • Pick<T, K>:选择对象的部分属性
  • Omit<T, K>:删除对象的部分属性

示例

interface User {
    id: number;
    name: string;
    email: string;
}

const partialUser: Partial<User> = { name: "Alice" };
const readonlyUser: Readonly<User> = { id: 1, name: "Bob", email: "bob@example.com" };
// readonlyUser.name = "Charlie"; // ❌ 报错


9. 泛型高级用法

(1)默认泛型类型

function createPair<T = string, U = number>(a: T, b: U): [T, U] {
    return [a, b];
}

const pair = createPair(); // 默认 T = string, U = number

(2)多重泛型约束

function merge<T extends object, U extends object>(obj1: T, obj2: U): T & U {
    return { ...obj1, ...obj2 };
}

const result = merge({ name: "Alice" }, { age: 30 });
console.log(result); // { name: "Alice", age: 30 }


10. 最佳实践

使用明确的泛型名称(如 T, U, V,避免 X, Y 这种无意义的名称)
优先使用 extends 进行类型约束
避免滥用 any,尽可能使用泛型
使用工具类型简化泛型代码


11. 参考资料


泛型是 TypeScript 强大的特性之一,能够提升代码的灵活性、复用性和类型安全性。熟练掌握泛型,将极大提升 TypeScript 编程能力! 🚀