如何从形如D的函数返回的类实例中推断Bar联合类型?
问题描述
能否从形如D的函数返回的类实例集合中,推断出所有传入bar参数值的联合类型type Bar = "quux" | "fubar"?
对应的代码如下:
type ConstructorA = {foo: string} class A { constructor({ foo }: ConstructorA) { // ... } } type ConstructorB = {foo: string, bar: string} class B { constructor({ foo, bar }: ConstructorB) { // ... } } class C { constructor({ foo, bar }: ConstructorB) { // ... } } const D = () => ({ A: new A({ foo: "baz" }), B: new B({ foo: "qux", bar: "quux" }), C: new C({ foo: "foobar", bar: "fubar" }), }); // 期望得到:type Bar = "quux" | "fubar"
解决方案
可以实现,核心思路是通过TypeScript的条件类型提取构造函数的参数类型,再筛选出bar属性的取值并生成联合类型。以下是两种可行方案:
方案1:显式关联构造函数类型(不修改类定义)
通过工具类型提取构造函数的参数,再遍历目标类的构造函数集合,筛选出bar的类型:
// 工具类型:提取类构造函数的第一个参数类型 type ConstructorArgs<T> = T extends new (args: infer A) => any ? A : never; // 定义D返回对象中键对应的构造函数类型映射 type DClassConstructors = { A: typeof A; B: typeof B; C: typeof C; }; // 遍历所有构造函数,提取bar的类型并生成联合类型 type Bar = { [K in keyof DClassConstructors]: ConstructorArgs<DClassConstructors[K]> extends { bar: infer B } ? B : never; }[keyof DClassConstructors]; // Bar最终被推断为 "quux" | "fubar"
方案2:让实例携带bar属性(修改类定义)
如果允许修改类的实现,将构造参数中的bar赋值给实例属性,就可以直接从实例类型中提取bar的类型:
// 修改类定义,添加实例属性 class A { constructor({ foo }: ConstructorA) { this.foo = foo; } foo: string; } class B { constructor({ foo, bar }: ConstructorB) { this.foo = foo; this.bar = bar; } foo: string; bar: string; } class C { constructor({ foo, bar }: ConstructorB) { this.foo = foo; this.bar = bar; } foo: string; bar: string; } // 直接从D的返回类型中提取bar的联合类型 type DReturnType = ReturnType<typeof D>; type Bar = DReturnType[keyof DReturnType] extends { bar: infer B } ? B : never; // Bar最终被推断为 "quux" | "fubar"
说明
- 方案1无需修改类的原有实现,但需要手动维护构造函数类型映射;如果
D中的键有增减,需要同步更新DClassConstructors。 - 方案2更简洁,但要求类将构造参数赋值给实例属性,适用于允许修改类定义的场景。
内容的提问来源于stack exchange,提问作者hollandThomas
相关产品推荐
相关产品推荐

