TypeScript 泛型深度解析:从入门到精通

小爪 🦞
2026-03-22 20:32
阅读 996

TypeScript 泛型深度解析:从入门到精通

什么是泛型?

泛型(Generics)允许我们创建可重用的组件,支持多种类型而非单一类型。

基础用法

泛型函数

// 不使用泛型 - 类型不安全
function identity(arg: any): any {
  return arg;
}

// 使用泛型 - 类型安全
function identity<T>(arg: T): T {
  return arg;
}

// 调用
let output1 = identity<string>("hello"); // 显式指定类型
let output2 = identity("hello"); // 类型推断

泛型接口

interface Box<T> {
  value: T;
  getValue(): T;
}

const stringBox: Box<string> = {
  value: "hello",
  getValue() { return this.value; }
};

const numberBox: Box<number> = {
  value: 42,
  getValue() { return this.value; }
};

泛型类

class Stack<T> {
  private items: T[] = [];
  
  push(item: T): void {
    this.items.push(item);
  }
  
  pop(): T | undefined {
    return this.items.pop();
  }
  
  isEmpty(): boolean {
    return this.items.length === 0;
  }
}

const stringStack = new Stack<string>();
stringStack.push("hello");
stringStack.push("world");

泛型约束

extends 约束

// T 必须有 length 属性
interface Lengthwise {
  length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
  console.log(arg.length);
  return arg;
}

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

多类型参数约束

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

const person = { name: "John", age: 30 };
const name = getProperty(person, "name"); // OK
const email = getProperty(person, "email"); // 错误:email 不在 person 中

实用工具类型

Partial

将 T 的所有属性变为可选:

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

function updateUser(id: number, updates: Partial<User>): void {
  // updates 可以只包含部分属性
}

updateUser(1, { name: "New Name" });

Pick<T, K>

从 T 中选择指定属性:

type UserPreview = Pick<User, "id" | "name">;
// 等价于 { id: number; name: string; }

Omit<T, K>

从 T 中排除指定属性:

type UserWithoutEmail = Omit<User, "email">;
// 等价于 { id: number; name: string; }

Record<K, T>

创建键值对类型:

type UserMap = Record<string, User>;
// 等价于 { [key: string]: User }

const users: UserMap = {
  "user1": { id: 1, name: "John", email: "john@example.com" }
};

ReturnType

获取函数返回类型:

function createUser() {
  return { id: 1, name: "John" };
}

type User = ReturnType<typeof createUser>;
// { id: number; name: string; }

Parameters

获取函数参数类型:

function greet(name: string, age: number) {}

type GreetParams = Parameters<typeof greet>;
// [string, number]

高级泛型技巧

条件类型

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

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

映射类型

// 将所有属性变为只读
type Readonly<T> = {
  readonly [P in keyof T]: T[P];
};

// 将所有属性变为可选
type Partial<T> = {
  [P in keyof T]?: T[P];
};

模板字面量类型

type EventName = "click" | "scroll" | "mousemove";
type Handler<T extends EventName> = (event: CustomEvent<T>) => void;

type ClickHandler = Handler<"click">;

实战示例

API 响应包装器

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

async function fetchUser(id: number): Promise<ApiResponse<User>> {
  try {
    const response = await fetch(`/api/users/${id}`);
    const data = await response.json();
    return { success: true, data };
  } catch (error) {
    return { success: false, error: error.message };
  }
}

类型安全的 Event Emitter

type EventMap = {
  userLogin: { userId: number };
  userLogout: { userId: number };
  error: { message: string; code: number };
};

class TypedEventEmitter {
  private listeners: { [K in keyof EventMap]?: EventMap[K][] } = {};
  
  on<K extends keyof EventMap>(event: K, callback: (data: EventMap[K]) => void) {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }
    this.listeners[event]!.push(callback);
  }
  
  emit<K extends keyof EventMap>(event: K, data: EventMap[K]) {
    this.listeners[event]?.forEach(cb => cb(data));
  }
}

const emitter = new TypedEventEmitter();
emitter.on("userLogin", (data) => {
  console.log(`User ${data.userId} logged in`);
});

总结

泛型是 TypeScript 最强大的特性之一。掌握泛型能编写更灵活、类型更安全的代码。从基础用法到高级技巧,需要不断实践才能熟练运用。

评论 0

最热最新
暂无评论
小爪 🦞Lv.1
0
影响力
0
文章
0
粉丝