类型收窄
从多种可能中确认当前类型,理解可辨识属性、in 与控制流路径。
本章目录CONTENTS ↓
一个值可能属于多种类型时,直接访问某个成员独有的属性会遇到报错。收窄让编译器利用已经执行的判断,确定当前位置还可能有哪些类型,从而允许安全的操作。
什么时候需要收窄
当参数是联合类型,而操作只适用于部分成员时,需要先判断实际情况。若当前位置已经确定为单一类型,直接使用即可。收窄利用类型中已有的信息;如果模型没有表达状态与数据的关联,单靠检查一个状态字段无法补全关系。
用可辨识属性确定成员
每个成员拥有同名属性,且该属性具有不同的字面量类型时,可以检查它来确定完整成员。
type Notice =
| { kind: "saved"; id: string }
| { kind: "failed"; error: string };
function describe(n: Notice): string {
if (n.kind === "saved") return n.id;
return n.error;
}进入 saved 分支时,n 被收窄为具有 id 的成员。这个分支返回后,后续位置只能由 failed 成员到达。完整业务模型如何选择,见关联的请求状态实战。
用属性存在性区分结构
联合没有统一的标签,但某属性只存在于其中一种结构时,也可以根据属性存在性判断。本例只使用必填属性。
type Payload = { userId: string } | { percent: number };
function show(p: Payload): string {
if ("userId" in p) return p.userId.toUpperCase();
return p.percent.toFixed(0);
}为什么分支结束后要重新看路径
收窄取决于哪些执行路径能到达当前位置。提前 return 会排除一条路径;仅执行一次打印不会。
function logPayload(p: Payload): void {
if ("userId" in p) console.log(p.userId);
// 此处两种成员都可能到达,不能直接访问 p.percent。
if ("percent" in p) console.log(p.percent);
}也可以使用 if/else,让每个操作都处在已确认的分支里。不要把规则简化成“if 外一定没有收窄”。事件回调里的外部变量与参数关联问题,放在事件处理器实战中讨论。
官方阅读
- Narrowing:可辨识联合、属性检查和控制流分析。
这一页,先记到这里。