TypeScript中无标识前缀的对象联合类型如何实现读取操作?
TypeScript中无标识对象联合类型的正确使用方式
问题场景
当使用无标识前缀的对象联合类型时,直接访问属性会触发TypeScript类型检查错误,比如:
function unionAsObject(a: { str: string } | { num: number }) { if (typeof a.str === 'string') { // 此处报错,TypeScript无法确定a是否包含str属性 } }
而基础类型联合、带标识的对象联合,TypeScript都能通过类型检查自动收窄类型:
基础类型联合示例
function unionAsType(a: string | number) { if (typeof a === 'string') { return a.indexOf('a'); // TypeScript识别此时a为string类型 } }
带标识的对象联合示例
function unionOfObjectsWithKeys(a: { type: 'str', str: string } | { type: 'num', num: number }) { if (a.type === 'str') { return a.str.indexOf('a'); // TypeScript通过type字段确定a的类型 } }
解决方案
1. 使用in操作符进行类型收窄
TypeScript支持通过in操作符检查对象是否包含目标属性,自动完成联合类型收窄:
function unionAsObject(a: { str: string } | { num: number }) { if ('str' in a) { // 此时TypeScript确定a是{ str: string }类型 return a.str.indexOf('a'); } else { // 自动推断a是{ num: number }类型 return a.num.toString(); } }
2. 自定义类型守卫函数
如果需要更复杂的类型判断逻辑,可以自定义返回类型谓词的守卫函数:
type ObjectUnion = { str: string } | { num: number }; function isStrObj(obj: ObjectUnion): obj is { str: string } { return 'str' in obj && typeof obj.str === 'string'; } function unionAsObject(a: ObjectUnion) { if (isStrObj(a)) { return a.str.indexOf('a'); } else { return a.num.toString(); } }
3. 优化Extract用法(不推荐,仅作补充)
你之前使用Extract的方式可以简化,无需额外变量:
type ObjectUnion = { str: string } | { num: number }; function unionAsObject(a: ObjectUnion) { const strObj = a as Extract<ObjectUnion, { str: string }>; if (strObj.str !== undefined) { return strObj.str.indexOf('a'); } }
不过这种方式需要手动类型断言,不如前两种方法简洁直观。
内容的提问来源于stack exchange,提问作者Luke
相关产品推荐
相关产品推荐

