TypeScript 可辨识联合与穷尽检查

解释如何用共同字面量字段建模有限业务状态,并使用 never 在新增成员时获得编译期提醒。

#type / concept #status / evergreen #tech / dev #resource / typescript

[!info] related notes

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 必然有 dataerror 必然有 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 会报错。它把“记得更新所有分支”从人工约定变成编译器检查。

设计边界

  • 判别字段应稳定、唯一且来自业务协议,例如 typestatuskind
  • 不要用多个互相矛盾的 boolean 表达有限状态。
  • 外部 JSON 仍需先运行时校验,才能安全成为该联合。
创建于 2026/7/29 更新于 2026/7/29