You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何基于另一类方法的条件类型推断类属性类型?

解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 00:22:11