如何基于另一类方法的条件类型推断类属性类型?
解决TypeScript类属性类型自动推断问题
核心思路
将Parent类改为泛型类,让它的obj类型依赖于构造时传入的构造函数类型;同时调整Builder的build方法签名,确保它能正确关联Parent的泛型类型,形成完整的类型推断链条。
修改后的代码
class ClassA { propString: string = ""; // 初始化避免类型报错 } class ClassB { propNumber: number = 0; // 初始化避免类型报错 } type TypeAConstructor = new () => ClassA; type TypeBConstructor = new () => ClassB; type ConstructorType = TypeAConstructor | TypeBConstructor; class Builder { body: ClassA | ClassB; constructor() { this.body = new ClassA(); // 初始化body } build<T extends ConstructorType>( Ctr: T, parent: Parent<InstanceType<T>> ): InstanceType<T> { // 直接比较构造函数引用,避免冗余实例化 const isClassA = Ctr === ClassA; this.body = isClassA ? new ClassA() : new ClassB(); // 泛型关联后,parent.obj类型与返回值匹配,无需宽泛断言 parent.obj = this.body as InstanceType<T>; return this.body as InstanceType<T>; } } // 泛型Parent类,T对应obj的实际类型 class Parent<T extends ClassA | ClassB> { obj: T; builder: Builder = new Builder(); constructor(Ctr: ConstructorType) { // TypeScript自动推断T为传入构造函数的实例类型 this.obj = this.builder.build(Ctr, this); } } // 使用示例 const parentA = new Parent(ClassA); parentA.obj.propString; // 类型正确,可正常访问string属性 const parentB = new Parent(ClassB); parentB.obj.propNumber; // 类型正确,可正常访问number属性
关键修改点说明
- 泛型Parent类:通过泛型参数
T约束obj的类型,构造时传入的构造函数会触发TypeScript自动推断T的具体类型(ClassA或ClassB)。 - Builder方法类型优化:
build方法的parent参数指定为Parent<InstanceType<T>>,确保parent.obj的类型与返回值类型严格匹配,消除类型不匹配报错。 - 减少冗余实例化:原代码中用
new Ctr()判断类型会额外创建实例,改为直接比较构造函数引用Ctr === ClassA,更高效且不影响类型判断逻辑。 - 安全类型断言:用
as InstanceType<T>替代原代码的as any,类型断言更精准,避免类型安全隐患。
替代方案(无需泛型Parent类)
如果不想让Parent成为泛型类,可通过构造函数赋值+类型守卫实现类型缩小:
class Parent { obj: ClassA | ClassB; builder: Builder = new Builder(); constructor(Ctr: ConstructorType) { const body = this.builder.build(Ctr, this); this.obj = body; // 使用时通过类型守卫缩小类型 if (this.obj instanceof ClassA) { this.obj.propString; // 类型为ClassA } else { this.obj.propNumber; // 类型为ClassB } } }
这种方案下obj仍是联合类型,但使用时可通过类型守卫获取具体类型,适合不需要在类定义阶段确定obj类型的场景。
内容的提问来源于stack exchange,提问作者Khanon
相关产品推荐
相关产品推荐

