TypeScript 可辨识联合与穷尽检查
解释如何用共同字面量字段建模有限业务状态,并使用 never 在新增成员时获得编译期提醒。
#type / concept
#status / evergreen
#tech / dev
#resource / typescript
[!info] related notes
- 前置:TypeScript 联合类型、收窄与类型守卫
- React 应用:useReducer
- 项目入口:BodySense MOC
TypeScript 可辨识联合与穷尽检查
一句话定义
可辨识联合让每个联合成员拥有同一个字面量判别字段,使编译器能根据该字段准确选择成员。
type TurnAction =
| { type: 'reset' }
| { type: 'hydrate'; state: TurnState }
| { type: 'answer'; interactionId: string };
为什么适合业务状态
相比一组可选字段,可辨识联合把有效组合写进类型:
type RequestState<T> =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success'; data: T }
| { status: 'error'; error: Error };
success 必然有 data,error 必然有 error,因此不需要在每个使用点猜测字段组合。
穷尽检查
function assertNever(value: never): never {
throw new Error(`Unhandled state: ${JSON.stringify(value)}`);
}
function label(state: RequestState<unknown>): string {
switch (state.status) {
case 'idle': return '等待';
case 'loading': return '加载中';
case 'success': return '完成';
case 'error': return state.error.message;
default: return assertNever(state);
}
}
新增联合成员后,未同步处理的 switch 会报错。它把“记得更新所有分支”从人工约定变成编译器检查。
设计边界
- 判别字段应稳定、唯一且来自业务协议,例如
type、status、kind。 - 不要用多个互相矛盾的 boolean 表达有限状态。
- 外部 JSON 仍需先运行时校验,才能安全成为该联合。