正在加载,请稍候…

高级 TypeScript:泛型、条件类型与模板字面量类型

掌握 TypeScript 高级类型系统:泛型约束、条件类型、映射类型、模板字面量类型及 infer 关键字,编写类型安全的代码。

高级 TypeScript:泛型、条件类型与模板字面量类型

高级 TypeScript 类型系统

TypeScript 的类型系统非常强大。掌握泛型、条件类型和模板字面量类型可以消除整类错误。

带约束的泛型

// 带约束的泛型
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { name: "Alice", age: 30 };
const name = getProperty(user, "name"); // 类型: string

// 多重约束
interface Serializable { serialize(): string; }
interface Identifiable { id: string; }

function saveEntity<T extends Serializable & Identifiable>(entity: T): void {
  const data = entity.serialize();
  database.save(entity.id, data);
}

高级 TypeScript:泛型、条件类型与模板字面量类型 插图

条件类型

// 基础条件类型
type IsString<T> = T extends string ? "yes" : "no";

// 提取数组元素类型
type ArrayElement<T> = T extends Array<infer E> ? E : never;
type Items = ArrayElement<string[]>; // string

// 深度只读
type DeepReadonly<T> = T extends object
  ? { readonly [P in keyof T]: DeepReadonly<T[P]> }
  : T;

// 异步返回类型
type AsyncReturn<T extends (...args: any) => Promise<any>> = 
  T extends (...args: any) => Promise<infer R> ? R : never;

infer 关键字

// 提取函数参数类型
type Parameters<T extends (...args: any) => any> =
  T extends (...args: infer P) => any ? P : never;

type ReturnType<T extends (...args: any) => any> =
  T extends (...args: any) => infer R ? R : never;

function greet(name: string, age: number): string { return name; }
type GreetParams = Parameters<typeof greet>; // [string, number]
type GreetReturn = ReturnType<typeof greet>;  // string

// 解包 Promise
type Awaited<T> = T extends Promise<infer V> ? Awaited<V> : T;
type Unwrapped = Awaited<Promise<Promise<string>>>; // string

高级 TypeScript:泛型、条件类型与模板字面量类型 插图

映射类型

// 自定义映射类型
type Nullable<T> = { [P in keyof T]: T[P] | null };

// 使用 'as' 重新映射键
type Getters<T> = {
  [K in keyof T as `get${Capitalize<string & K>}`]: () => T[K]
};

interface Person { name: string; age: number; }
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number }

// 按值类型过滤键
type KeysOfType<T, ValueType> = {
  [K in keyof T]: T[K] extends ValueType ? K : never
}[keyof T];

interface Mixed { id: number; name: string; active: boolean; }
type StringKeys = KeysOfType<Mixed, string>; // "name"

模板字面量类型

// 类型安全的事件系统
type EventName = "click" | "focus" | "blur";
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"

// CSS 属性构建器
type Side = "top" | "right" | "bottom" | "left";
type Margin = `margin-${Side}`;

// 类型安全的对象路径
type PathKeys<T, Prefix extends string = ""> = {
  [K in keyof T & string]: T[K] extends object
    ? PathKeys<T[K], `${Prefix}${K}.`>
    : `${Prefix}${K}`;
}[keyof T & string];

interface Config { db: { host: string; port: number }; }
type ConfigPaths = PathKeys<Config>; // "db.host" | "db.port"

高级 TypeScript:泛型、条件类型与模板字面量类型 插图

可辨识联合类型

type LoadingState<T> =
  | { status: "idle" }
  | { status: "loading" }
  | { status: "success"; data: T }
  | { status: "error"; error: Error };

function renderUser(state: LoadingState<User>) {
  switch (state.status) {
    case "success": return state.data.name; // TypeScript 知道 data 存在
    case "error": return state.error.message;
    default: return "Loading...";
  }
}

// 穷举检查
function assertNever(x: never): never {
  throw new Error(`Unexpected: ${x}`);
}

总结

TypeScript 的类型系统值得投入:

  • 泛型 消除重复同时保持类型安全
  • 条件类型 根据运行时形状转换类型
  • infer 从复杂泛型中提取类型
  • 映射类型 系统地转换现有类型
  • 模板字面量类型 为字符串模式带来类型安全