TypeScript:展开联合类型对象后如何实现类型区分?
问题:展开联合类型对象后如何维持类型区分
先定义如下联合类型:
type ExampleType = { type: "number", data: 0 } | { type: "string", data: "", }
使用展开操作符解构后,type 与剩余的 data 变量失去了类型关联,无法通过type的判断收窄data的类型:
const example = (param: ExampleType) => { const {type, ...data} = param; if (type === 'number') { const result = data; // result仍为联合类型,未正确收窄 } }
但直接访问原对象属性时,类型收窄正常工作:
const example = (param: ExampleType) => { if (param.type === "number") { const result1 = param.data; // result1类型为0,符合预期 } }
请问能否通过展开操作符实现联合类型的区分?如果可以,具体怎么做?
解决方案
可以实现,核心是让TypeScript重新建立type和剩余data的类型关联,以下是两种可行方案:
方案一:自定义工具类型 + 类型断言
先定义工具类型,根据type字段提取对应联合成员的剩余属性类型:
type ExtractByType<T, Type extends T["type"]> = T extends { type: Type } ? Omit<T, "type"> : never;
之后在判断type后,对data做类型断言:
const example = (param: ExampleType) => { const {type, ...data} = param; if (type === 'number') { const result = data as ExtractByType<ExampleType, "number">; // result 类型为 { data: 0 },符合预期 } if (type === 'string') { const result = data as ExtractByType<ExampleType, "string">; // result 类型为 { data: "" },符合预期 } }
方案二:重构原结构对象
把解构出的type和data重新组合成原联合类型的对象,让TypeScript自动完成类型收窄:
const example = (param: ExampleType) => { const {type, ...data} = param; const restructured = { type, ...data } as ExampleType; if (restructured.type === 'number') { const result = restructured.data; // 类型为0,符合预期 } }
原理说明
TypeScript解构剩余属性时,会将联合类型的剩余部分合并为无关联的联合,丢失了原联合成员中type与其他属性的绑定关系。因此需要手动通过工具类型或重构对象的方式,重新建立这种关联,才能实现类型收窄。
内容的提问来源于stack exchange,提问作者Денис Кирин
相关产品推荐
相关产品推荐

