先记住这个答案
TypeScript 可以用 true 和 false 这两个布尔字面量作为联合成员的标签,例如成功成员拥有 ok: true 和 data,失败成员拥有 ok: false 和 error。判断 ok 后即可使用对应负载。若只定义一个对象,字段为 ok: boolean、data 可选、error 可选,则没有建立成功必有数据的关系。示例应在严格类型检查配置下验证,尤其注意空值相关选项。状态可能增加等待、取消等情况时,语义明确的字符串标签通常比不断叠加布尔开关更容易维护。
- 布尔字面量可以关联两个不同负载成员
- 宽 boolean 加可选字段无法表达完整二态契约
- 判断标签与判断 data 的真假不是同一件事
布尔标签怎样保留字段关联
操作结果只有成功与失败两种稳定状态时,ok 标签比较直观。关键是类型由两个完整成员组成:成功分支的数据不是可选,失败分支的错误也不是可选。这样构造函数与消费函数都受到同一关联约束。
示例成功数据允许为零,所以判断依据必须是 ok,而不能是 data 的真值。检查 true 后使用数字格式化,false 分支使用错误文本。缺少数据的成功对象在编译期被拒绝,避免把异常组合一路传到界面上才发现。
type CountResult =
| { ok: true; data: number }
| { ok: false; error: string };
function renderCount(result: CountResult): string {
if (result.ok === true) return result.data.toFixed(0);
return result.error;
}
const empty: CountResult = { ok: true, data: 0 };
// @ts-expect-error 成功成员不能缺少 data
const missing: CountResult = { ok: true };零是有效成功数据,标签比较不会误把它当成失败。预期错误验证 true 成员与必需 data 保持关联,而不是所有字段都随布尔值变成可有可无。
为什么宽 boolean 模型不够
如果所有字段都放进同一个接口,ok 为 boolean,data 与 error 均可选,那么 ok 为 true 时依然允许没有 data。编译器保留可选提示是忠实反映模型,并非不支持布尔收窄。应改变联合结构,而不是在成功分支反复追加非空断言。
对象构造时 ok 也可能被推断成宽 boolean,无法直接满足指定字面量成员。可以让工厂函数明确返回结果联合,或在字面量定义处提供恰当上下文。不要把任何布尔表达式都断言成 true,这会抹去失败可能性并破坏结果契约。
二态标签什么时候需要升级
如果请求过程还要表达空闲、加载、取消和重试,单个成功布尔值不足以描述所有状态,多个布尔开关又容易形成矛盾组合。此时用明确的字符串状态联合,可以直接表达每个阶段的数据需求,减少调用方猜测多个开关关系。
旧项目关闭严格空值检查时,部分分支推断和可选字段行为可能不同,应以项目实际配置运行最小示例。显式比较 true 或 false 可以使意图更清楚,但不能替代正确建模和严格配置。接口协议若来自外部,仍要确认标签确实是布尔值而不是字符串。
容易答错的地方
- ok 是 boolean 就能证明成功数据存在
- 单个宽布尔字段与可选 data 之间没有必然关联,模型仍允许错误组合;需要分别声明 true 与 false 对应的完整联合成员。
- 成功判断可以直接用 if(result.data)
- 成功数据可能是零、空串或 false,真假判断会误伤合法值;应根据专门状态标签判断,再按该分支的数据契约进行展示。
面试官还会怎么问?
只有两个状态一定应该选布尔标签吗?
不必,布尔值适合含义明确的成功失败;如果标签本身难以表达业务含义,两个字符串状态也可能更便于日志、协议和后续扩展。
为什么从接口读取的 ok 不能直接相信?
实际响应可能返回字符串、缺失字段或与数据不一致的状态,静态类型不会检查网络内容;解析层仍需验证每个成员的完整协议。
布尔标签后面新增 pending 应该怎么做?
应把状态模型调整成能明确表达等待阶段的联合,并更新所有消费者;不要随意把 pending 映射成 false,导致失败和等待混成同一语义。
参考资料
示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。