引言
TypeScript 的类型系统非常强大,图灵完备。但很多开发者只使用到了其中很小的一部分。本文分享几个我在日常开发中使用的高级类型技巧。
1. 条件类型 (Conditional Types)
条件类型让你可以根据类型关系来选择不同的类型:
type IsString<T> = T extends string ? "yes" : "no";
type A = IsString<"hello">; // "yes"
type B = IsString<42>; // "no"
实战:提取 Promise 的值类型
type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T;
type Result = Awaited<Promise<Promise<number>>>; // number
2. 模板字面量类型
TypeScript 4.1+ 支持在类型层面操作字符串:
type EventName = "click" | "focus" | "blur";
type HandlerName = `on${Capitalize<EventName>}`;
// "onClick" | "onFocus" | "onBlur"
实战:类型安全的路由
type Route =
| "/"
| "/posts"
| `/posts/${string}`
| "/about";
function navigate(path: Route) {
// path 现在是类型安全的
}
navigate("/posts/hello-world"); // ✅
navigate("/admin"); // ❌ 类型错误
3. satisfies 操作符
TypeScript 4.9 引入的 satisfies 让你在保持类型推断的同时进行类型检查:
// 使用 satisfies — 既有类型检查,又保留字面量类型
const config = {
theme: "dark",
version: 1,
} satisfies Record<string, string | number>;
// config.theme 的类型是 "dark",不是 string!
4. const 类型断言
const colors = ["red", "green", "blue"] as const;
// 类型是 readonly ["red", "green", "blue"]
// 而不是 string[]
type Color = (typeof colors)[number]; // "red" | "green" | "blue"
5. 类型谓词 (Type Predicates)
自定义类型守卫让你的代码更安全:
interface User {
type: "user";
name: string;
}
interface Admin {
type: "admin";
name: string;
permissions: string[];
}
type Person = User | Admin;
function isAdmin(person: Person): person is Admin {
return person.type === "admin";
}
// 使用
if (isAdmin(person)) {
// TypeScript 知道这里 person 是 Admin
console.log(person.permissions);
}
总结
这些高级类型技巧可以帮助你:
- 减少运行时错误 — 在编译期就发现问题
- 提升开发体验 — 更好的自动补全和类型提示
- 编写自文档化的代码 — 类型即文档
TypeScript 的类型系统是一座金矿,值得深入挖掘。
小贴士:如果你刚开始接触这些概念,建议一次只学一个,在实际项目中使用熟练后再学下一个。