TypeScript元组类型收窄疑问:两类场景类型推断为何不同?
TypeScript联合元组类型推断差异问题解析
下面两个TypeScript场景中,都是返回包含不同类型的联合元组,但类型推断表现却不一致:
场景1:返回两组对象+undefined的联合元组
export function functionThatReturnsTurpleObjects(): | [{ a: number }, undefined] | [undefined, { a: number }] { if (Math.random() > 0.5) { return [undefined, { a: 1 }]; } return [{ a: 1 }, undefined]; } function execute1() { const [res1, res2] = functionThatReturnsTurpleObjects(); if (res2) { return res2; } // TypeScript可以正确推断res1不可能为undefined res1.a; }
场景2:返回对象+undefined和undefined+字符串的联合元组
function functionThatReturnsTurpleObjectAndString(): | [{ a: number }, undefined] | [undefined, string] { if (Math.random() > 0.5) { return [undefined, "1"]; } return [{ a: 1 }, undefined]; } function execute2() { const [res1, res2] = functionThatReturnsTurpleObjectAndString(); if (res2) { return res2; } // TypeScript抛出错误:TS18048: res1 is possibly undefined,但实际res1不可能为undefined res1.a; }
差异原因解析
这是因为TypeScript的联合类型收窄规则在处理元组时,依赖元组对应位置类型的可辨识性:
- 场景1中,联合元组的第二个元素非
undefined时类型完全一致(都是{a: number})。当res2被收窄为{a: number}时,TypeScript能明确排除[{a: number}, undefined]分支;当res2为undefined时,自然锁定到[{a: number}, undefined]分支,因此能正确推断res1不可能为undefined。 - 场景2中,联合元组的第二个元素非
undefined时类型不同({a: number}vsstring)。当res2为undefined时,TypeScript无法仅通过这一点反向锁定唯一分支——因为两个分支的第二个位置都可能是undefined,且第一个位置的类型没有共同可辨识特征,导致无法自动推断res1此时必然是{a: number}。
修复方案
要让场景2的推断正常工作,可以手动添加类型断言,或者使用明确的类型守卫:
// 方案1:类型断言 function execute2Fixed() { const [res1, res2] = functionThatReturnsTurpleObjectAndString(); if (res2) { return res2; } (res1 as {a: number}).a; } // 方案2:自定义类型守卫 function isFirstTuple(tuple: ReturnType<typeof functionThatReturnsTurpleObjectAndString>): tuple is [{a: number}, undefined] { return tuple[0] !== undefined; } function execute2Fixed2() { const tuple = functionThatReturnsTurpleObjectAndString(); if (tuple[1]) { return tuple[1]; } if (isFirstTuple(tuple)) { tuple[0].a; } }
内容的提问来源于stack exchange,提问作者Evgeniy Lyahov
相关产品推荐
相关产品推荐

