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

TypeScript 工厂方法场景下如何正确声明不同产品的对应类型?

错误根源

你定义的抽象父类Product将配置属性config声明为ConfigI联合类型,TypeScript 对联合类型的属性访问默认只允许访问所有子类型共有的属性,而你的ConfigProduct1和ConfigProduct2没有公共属性,因此不管是在子类中访问独有属性arg1/arg2,还是外部通过Product类型的实例访问配置属性,都会触发类型报错。另外你的工厂方法没有做类型映射,TypeScript 无法根据传入的TYPE枚举值匹配对应的产品类型和配置类型。


修复方案

1. 将抽象父类改造为泛型类

给Product增加泛型参数,约束泛型必须继承自ConfigI,让子类继承时可以指定具体的配置类型:

// 父类增加泛型参数
abstract class Product<T extends ConfigI> {
    protected config: T
    get cfg(): T {
        return this.config
    }
    constructor(config: T) {
        this.config = config
    }

    abstract foo(): void
}

2. 子类继承时指定具体配置类型

子类继承Product时传入对应产品的配置类型,TypeScript 就能识别子类中config的具体类型:

class ConcreteProduct1 extends Product<ConfigProduct1> {
    foo() {
        console.log(this.config.arg1) // 无报错
    }
}

class ConcreteProduct2 extends Product<ConfigProduct2> {
    foo() {
        console.log(this.config.arg2) // 无报错
    }
}

3. 给工厂方法增加重载做类型映射

通过函数重载让 TypeScript 可以根据传入的产品类型,自动匹配对应的配置类型和返回值类型:

class Creator {
    // 重载1:产品1类型对应产品1配置和产品1实例
    static createProduct(type: TYPE.PRODUCT1, config: ConfigProduct1): ConcreteProduct1
    // 重载2:产品2类型对应产品2配置和产品2实例
    static createProduct(type: TYPE.PRODUCT2, config: ConfigProduct2): ConcreteProduct2
    // 实现签名
    static createProduct(type: TYPE, config: ConfigI) {
        switch(type) {
            case TYPE.PRODUCT1:
                return new ConcreteProduct1(config)
            case TYPE.PRODUCT2:
                return new ConcreteProduct2(config)
            default:
                throw new Error('Wrong Product type')
        }
    }
}

此时调用工厂方法时,TypeScript 会自动做类型校验:传入TYPE.PRODUCT1时必须传ConfigProduct1类型的配置,返回值也会自动推断为ConcreteProduct1类型。

4. 外部使用产品实例时的类型处理

如果需要在其他类中访问产品的具体配置属性,有两种可选方案:

  • 方案1:给使用类也增加泛型约束
class ProductUsing<T extends Product<ConfigI>> {
    protected product: T
    constructor(product: T) {
        this.product = product
    }

    bar() {
        // 当传入的product是ConcreteProduct1实例时,访问arg1无报错
        console.log(this.product.cfg.arg1)
    }
}
  • 方案2:先做类型收窄再访问属性
    如果无法确定传入的产品类型,可以先通过属性判断收窄配置的联合类型:
bar() {
    const cfg = this.product.cfg
    if ('arg1' in cfg) {
        console.log(cfg.arg1) // 收窄为ConfigProduct1类型,无报错
    } else {
        console.log(cfg.arg2) // 收窄为ConfigProduct2类型,无报错
    }
}

内容的提问来源于stack exchange,提问作者yiooxir

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 09:45:03