如何避免TypeScript对对象字面量联合类型进行规范化?
如何让TypeScript推断非规范化的判别式联合类型?
问题场景
给定以下TypeScript函数,我们通过as const断言保留返回对象的字面量类型:
function Foo(num: number) { switch (num) { case 0: return { type: "Quz", str: 'string', } as const; case 1: return { type: "Bar", 1: 'value' } as const; default: throw new Error("Unknown discriminant: " + num); } }
TypeScript默认会对判别式联合类型做规范化处理,自动为每个联合成员添加其他分支的属性作为可选undefined类型,最终推断的返回类型为:
function Foo(num: number): { readonly type: "Quz"; readonly str: "string"; readonly 1?: undefined; } | { readonly type: "Bar"; readonly 1: "value"; readonly str?: undefined; }
但我们需要的是更简洁的、无冗余可选属性的联合类型:
{ type: "Quz"; str: "string"; } | { type: "Bar"; 1: "value"; }
要求:不手动指定函数返回类型,不提前枚举所有输出分支,仅通过编译器推断得到目标类型。
解决方案
方法一:自定义工具类型过滤冗余属性
通过定义工具类型移除联合类型中值为undefined的可选属性,同时保留原字面量类型约束:
- 定义工具类型:
// 移除对象中值为undefined的可选属性,同时将只读属性转为普通属性 type OmitUndefinedOptionalProps<T> = T extends object ? { [K in keyof T as T[K] extends undefined ? never : K]: T[K] extends readonly infer U ? U : T[K] } : T;
- 包装原函数并转换返回类型:
type OmitUndefinedOptionalProps<T> = T extends object ? { [K in keyof T as T[K] extends undefined ? never : K]: T[K] extends readonly infer U ? U : T[K] } : T; const Foo = ((num: number) => { switch (num) { case 0: return { type: "Quz", str: 'string', } as const; case 1: return { type: "Bar", 1: 'value' } as const; default: throw new Error("Unknown discriminant: " + num); } }) as unknown as (num: number) => OmitUndefinedOptionalProps<ReturnType<typeof Foo>>;
此时Foo的返回类型会被推断为目标类型,且无需手动编写每个分支的类型定义。
方法二:使用satisfies断言(TypeScript 4.9+)
如果不需要保留属性的只读特性,可以去掉as const,改用satisfies断言确保类型字面量的正确性:
// 定义基础判别式类型,仅做类型检查不影响推断 type DiscriminantBase = { type: string }; function Foo(num: number) { switch (num) { case 0: return { type: "Quz", str: 'string' } satisfies DiscriminantBase; case 1: return { type: "Bar", 1: 'value' } satisfies DiscriminantBase; default: throw new Error("Unknown discriminant: " + num); } }
这种方式下,TypeScript会直接推断出非规范化的联合类型,属性为可写状态。
内容的提问来源于stack exchange,提问作者xtr
相关产品推荐
相关产品推荐

