用编译器替你检查的联合类型来建模应用程序的各种状态。
在 Kodokon 中打开本课字面量类型把一个值限制为确切的内容:是 'info' 而不是 string。它是那些无法被误用的 API 的基石:编译器会拒绝列表之外的任何值,而你的编辑器会提供自动补全。
type Level = "info" | "warn" | "error";
function log(level: Level, message: string): void {
console.log(`[${level}] ${message}`);
}
log("info", "Server started");
// log("fatal", "Boom"); -> rejected by the compiler下一步是组合那些共享一个公共字面量属性的对象类型,这个属性被称为辨识标记。举例来说,网络请求的每一种状态只携带属于它自己的数据:在加载中时访问 data 根本就是不可能的。
type ApiState =
| { status: "loading" }
| { status: "success"; data: string[] }
| { status: "error"; message: string };
function render(state: ApiState): string {
switch (state.status) {
case "loading":
return "Loading...";
case "success":
return state.data.join(", ");
case "error":
return state.message;
}
}在每个 case 中,TypeScript 都会收窄类型:在 case 'error' 之后,state.message 存在而 state.data 不存在。这个被称为类型收窄(narrowing)的机制取代了脆弱的手动检查。再加上一个穷尽性守卫,把整件事彻底锁定。
function assertNever(value: never): never {
throw new Error("Unhandled case: " + String(value));
}
function label(state: ApiState): string {
switch (state.status) {
case "loading": return "In progress";
case "success": return "Done";
case "error": return "Failed";
default: return assertNever(state);
}
}