TypeScript 类型体操入门

学习 TypeScript 高级类型编程技巧,从基础到进阶的类型体操指南。

TypeScript 的类型系统是图灵完备的,这意味着你可以用类型做很多有趣的事情。让我们从基础开始,逐步探索类型体操的世界。

基础类型工具

条件类型

条件类型是类型体操的基础:

type IsString<T> = T extends string ? true : false;
type A = IsString<"hello">; // true
type B = IsString<42>; // false

映射类型

映射类型允许你转换对象类型的每个属性:

type Readonly<T> = {
readonly [K in keyof T]: T[K];
};
type Optional<T> = {
[K in keyof T]?: T[K];
};

实用类型实现

实现 Pick

type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
interface User {
id: number;
name: string;
email: string;
}
type UserPreview = MyPick<User, "id" | "name">;
// { id: number; name: string }

实现 Omit

type MyOmit<T, K extends keyof T> = {
[P in keyof T as P extends K ? never : P]: T[P];
};
type UserWithoutEmail = MyOmit<User, "email">;
// { id: number; name: string }

递归类型

TypeScript 支持递归类型定义:

type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object
? DeepReadonly<T[K]>
: T[K];
};
type NestedObject = {
a: {
b: {
c: number;
};
};
};
type ReadonlyNested = DeepReadonly<NestedObject>;

模板字面量类型

TypeScript 4.1 引入了模板字面量类型:

type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">; // "onClick"
type FocusEvent = EventName<"focus">; // "onFocus"
// 更复杂的例子
type CSSProperty = "margin" | "padding";
type CSSDirection = "top" | "right" | "bottom" | "left";
type CSSSpacing = `${CSSProperty}-${CSSDirection}`;
// "margin-top" | "margin-right" | ... | "padding-left"

类型推断

使用 infer 关键字提取类型:

type ReturnType<T> = T extends (...args: any[]) => infer R ? R : never;
type ArrayElement<T> = T extends (infer E)[] ? E : never;
type Fn = () => string;
type Result = ReturnType<Fn>; // string
type Arr = number[];
type Elem = ArrayElement<Arr>; // number

实战:类型安全的事件系统

type Events = {
click: { x: number; y: number };
focus: { target: HTMLElement };
submit: { data: FormData };
};
type EventHandler<E extends keyof Events> = (
event: Events[E]
) => void;
function on<E extends keyof Events>(
event: E,
handler: EventHandler<E>
): void {
// 实现
}
// 类型安全的使用
on("click", (e) => {
console.log(e.x, e.y); // ✅ 类型正确
});
on("submit", (e) => {
console.log(e.data); // ✅ 类型正确
});

类型体操不仅是炫技,更是构建类型安全应用的有力工具。掌握这些技巧,让编译器成为你最好的助手。

评论