Skip to content

generics.ts

文件信息

  • 📄 原文件:02_generics.ts
  • 🔤 语言:typescript

TypeScript 泛型 本文件介绍 TypeScript 中的泛型编程。

完整代码

typescript
/**
 * ============================================================
 *                TypeScript 泛型
 * ============================================================
 * 本文件介绍 TypeScript 中的泛型编程。
 * ============================================================
 */

console.log("=".repeat(60));
console.log("1. 泛型基础");
console.log("=".repeat(60));

// ============================================================
//                    1. 泛型基础
// ============================================================

// --- 泛型函数 ---
console.log("\n--- 泛型函数 ---");

// 没有泛型 - 类型信息丢失
function identityAny(value: any): any {
    return value;
}

// 使用泛型 - 保留类型信息
function identity<T>(value: T): T {
    return value;
}

// 显式指定类型
const str = identity<string>("hello");
console.log("identity<string>:", str);

// 类型推断
const num = identity(42);
console.log("identity(42):", num);

// --- 多个类型参数 ---
console.log("\n--- 多个类型参数 ---");

function pair<T, U>(first: T, second: U): [T, U] {
    return [first, second];
}

const result = pair<string, number>("age", 25);
console.log("pair:", result);

function swap<T, U>(tuple: [T, U]): [U, T] {
    return [tuple[1], tuple[0]];
}

console.log("swap:", swap([1, "one"]));

// --- 泛型约束 ---
console.log("\n--- 泛型约束 ---");

interface Lengthwise {
    length: number;
}

function logLength<T extends Lengthwise>(value: T): T {
    console.log(`  长度: ${value.length}`);
    return value;
}

logLength("hello");
logLength([1, 2, 3]);
// logLength(123);  // 错误:number 没有 length 属性

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

const person = { name: "Alice", age: 25 };
console.log("getProperty:", getProperty(person, "name"));
// getProperty(person, "email");  // 错误:email 不是 person 的键


console.log("\n" + "=".repeat(60));
console.log("2. 泛型接口和类型");
console.log("=".repeat(60));

// ============================================================
//                    2. 泛型接口和类型
// ============================================================

// --- 泛型接口 ---
console.log("\n--- 泛型接口 ---");

interface Container<T> {
    value: T;
    getValue(): T;
    setValue(value: T): void;
}

class Box<T> implements Container<T> {
    constructor(public value: T) {}

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

    setValue(value: T): void {
        this.value = value;
    }
}

const stringBox = new Box<string>("hello");
console.log("stringBox:", stringBox.getValue());

const numberBox = new Box(42);  // 类型推断
console.log("numberBox:", numberBox.getValue());

// --- 泛型类型别名 ---
console.log("\n--- 泛型类型别名 ---");

type Result<T, E = Error> = {
    success: true;
    data: T;
} | {
    success: false;
    error: E;
};

function divide(a: number, b: number): Result<number> {
    if (b === 0) {
        return { success: false, error: new Error("除数不能为零") };
    }
    return { success: true, data: a / b };
}

const divResult = divide(10, 2);
if (divResult.success) {
    console.log("结果:", divResult.data);
} else {
    console.log("错误:", divResult.error.message);
}

// --- 泛型默认类型 ---
console.log("\n--- 泛型默认类型 ---");

interface ApiResponse<T = any> {
    code: number;
    message: string;
    data: T;
}

const response1: ApiResponse<string[]> = {
    code: 200,
    message: "success",
    data: ["a", "b", "c"]
};

const response2: ApiResponse = {  // 使用默认类型 any
    code: 200,
    message: "success",
    data: { key: "value" }
};

console.log("response1:", response1);
console.log("response2:", response2);


console.log("\n" + "=".repeat(60));
console.log("3. 泛型类");
console.log("=".repeat(60));

// ============================================================
//                    3. 泛型类
// ============================================================

// --- 泛型栈 ---
console.log("\n--- 泛型栈 ---");

class Stack<T> {
    private items: T[] = [];

    push(item: T): void {
        this.items.push(item);
    }

    pop(): T | undefined {
        return this.items.pop();
    }

    peek(): T | undefined {
        return this.items[this.items.length - 1];
    }

    isEmpty(): boolean {
        return this.items.length === 0;
    }

    size(): number {
        return this.items.length;
    }
}

const numberStack = new Stack<number>();
numberStack.push(1);
numberStack.push(2);
numberStack.push(3);

console.log("peek:", numberStack.peek());
console.log("pop:", numberStack.pop());
console.log("size:", numberStack.size());

// --- 泛型队列 ---
console.log("\n--- 泛型队列 ---");

class Queue<T> {
    private items: T[] = [];

    enqueue(item: T): void {
        this.items.push(item);
    }

    dequeue(): T | undefined {
        return this.items.shift();
    }

    front(): T | undefined {
        return this.items[0];
    }

    isEmpty(): boolean {
        return this.items.length === 0;
    }
}

const taskQueue = new Queue<string>();
taskQueue.enqueue("任务1");
taskQueue.enqueue("任务2");
taskQueue.enqueue("任务3");

console.log("front:", taskQueue.front());
console.log("dequeue:", taskQueue.dequeue());
console.log("front after dequeue:", taskQueue.front());


console.log("\n" + "=".repeat(60));
console.log("4. 工具类型");
console.log("=".repeat(60));

// ============================================================
//                    4. 工具类型
// ============================================================

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

// --- Partial<T> ---
console.log("\n--- Partial<T> ---");
type PartialUser = Partial<User>;

function updateUser(id: number, updates: Partial<User>): void {
    console.log(`更新用户 ${id}:`, updates);
}

updateUser(1, { name: "Bob" });  // 只更新部分字段

// --- Required<T> ---
console.log("\n--- Required<T> ---");
interface Config {
    host?: string;
    port?: number;
}

type RequiredConfig = Required<Config>;
const config: RequiredConfig = {
    host: "localhost",
    port: 3000  // 必须提供
};
console.log("config:", config);

// --- Readonly<T> ---
console.log("\n--- Readonly<T> ---");
type ReadonlyUser = Readonly<User>;

const user: ReadonlyUser = {
    id: 1,
    name: "Alice",
    email: "[email protected]",
    age: 25
};
// user.name = "Bob";  // 错误:只读

// --- Pick<T, K> ---
console.log("\n--- Pick<T, K> ---");
type UserBasic = Pick<User, "id" | "name">;

const basic: UserBasic = {
    id: 1,
    name: "Alice"
};
console.log("picked:", basic);

// --- Omit<T, K> ---
console.log("\n--- Omit<T, K> ---");
type UserWithoutEmail = Omit<User, "email">;

const noEmail: UserWithoutEmail = {
    id: 1,
    name: "Alice",
    age: 25
};
console.log("omitted:", noEmail);

// --- Record<K, T> ---
console.log("\n--- Record<K, T> ---");
type Status = "pending" | "active" | "completed";
type StatusCount = Record<Status, number>;

const counts: StatusCount = {
    pending: 5,
    active: 10,
    completed: 20
};
console.log("record:", counts);

// --- Exclude<T, U> 和 Extract<T, U> ---
console.log("\n--- Exclude 和 Extract ---");
type AllTypes = string | number | boolean | null | undefined;

type NonNullable2 = Exclude<AllTypes, null | undefined>;
// 结果: string | number | boolean

type OnlyPrimitives = Extract<AllTypes, string | number>;
// 结果: string | number

// --- ReturnType<T> ---
console.log("\n--- ReturnType<T> ---");
function createUser2(): { id: number; name: string } {
    return { id: 1, name: "Alice" };
}

type CreatedUser = ReturnType<typeof createUser2>;
console.log("ReturnType:", {} as CreatedUser);

// --- Parameters<T> ---
console.log("\n--- Parameters<T> ---");
function greet2(name: string, age: number): string {
    return `Hello, ${name}! You are ${age}.`;
}

type GreetParams = Parameters<typeof greet2>;
// 结果: [string, number]


console.log("\n" + "=".repeat(60));
console.log("5. 条件类型");
console.log("=".repeat(60));

// ============================================================
//                    5. 条件类型
// ============================================================

// --- 基本条件类型 ---
console.log("\n--- 条件类型 ---");

type IsString<T> = T extends string ? true : false;

type A = IsString<string>;  // true
type B = IsString<number>;  // false

// --- infer 关键字 ---
type GetReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

function foo(): string { return "hello"; }
function bar(): number { return 42; }

type FooReturn = GetReturnType<typeof foo>;  // string
type BarReturn = GetReturnType<typeof bar>;  // number

// 获取数组元素类型
type ArrayElement<T> = T extends (infer E)[] ? E : T;

type NumElement = ArrayElement<number[]>;  // number
type StrElement = ArrayElement<string[]>;  // string

// --- 分布式条件类型 ---
type ToArray<T> = T extends any ? T[] : never;

type StrOrNumArray = ToArray<string | number>;
// 结果: string[] | number[]


console.log("\n【总结】");
console.log(`
泛型基础:
- <T> 声明类型参数
- 可以有多个类型参数 <T, U>
- extends 添加约束
- keyof 获取键类型

泛型使用场景:
- 函数:function fn<T>(arg: T): T
- 接口:interface Box<T> { value: T }
- 类:class Stack<T> {}
- 类型别名:type Result<T> = ...

内置工具类型:
- Partial<T> - 所有属性可选
- Required<T> - 所有属性必需
- Readonly<T> - 所有属性只读
- Pick<T, K> - 选取部分属性
- Omit<T, K> - 排除部分属性
- Record<K, T> - 键值对类型
- Exclude<T, U> - 从联合类型排除
- Extract<T, U> - 从联合类型提取
- ReturnType<T> - 函数返回类型
- Parameters<T> - 函数参数类型

条件类型:
- T extends U ? X : Y
- infer 推断类型
`);

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布