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

如何结合工厂模式与泛型基类保障TypeScript类型安全?

泛型基类工厂模式的TypeScript类型推断问题修复

问题场景

使用TypeScript实现结合泛型基类的工厂模式时,动态创建类实例后调用方法出现类型推断错误。简化代码如下:

abstract class BaseClass<TArg> {
  async getArgsArray(): Promise<TArg[]> {
    return await fetch("...").then(resp => resp.json()) as TArg[]
  }
}

type Class1Arg = { myValue: string }
class Class1 extends BaseClass<Class1Arg> {
  methodWithArgs(args: Class1Arg[]) {
    return args[0]?.myValue
  }
}

type Class2Arg = { myOtherValue: string }
class Class2 extends BaseClass<Class2Arg> {
  methodWithArgs(args: Class2Arg[]) {
    return args[0]?.myOtherValue
  }
}

async function getFactoryKey(): Promise<"class1" | "class2"> {
  return await fetch("...").then(resp => resp.json()) as Promise<"class1" | "class2">
}

const classes = {
  class1: Class1,
  class2: Class2
}

function factory<K extends keyof typeof classes>(
  key: K
): InstanceType<(typeof classes)[K]> {
  const TransformerClass = classes[key]
  return new TransformerClass() as InstanceType<(typeof classes)[K]>
}

async function test() {
  const key = await getFactoryKey()
  const myClass = factory(key)
  const args = await myClass.getArgsArray()
  
  // 此处触发TypeScript错误
  myClass.methodWithArgs(args)
}

错误信息

Argument of type 'Promise<Class2Arg[]> | Promise<Class1Arg[]>' is not assignable to parameter of type 'Class2Arg & Class1Arg'.
Type 'Promise<Class2Arg[]>' is not assignable to type 'Class2Arg & Class1Arg'.
  Property 'myOtherValue' is missing in type 'Promise<Class2Arg[]>' but required in type 'Class2Arg'.

问题根源

TypeScript无法对联合类型实例进行关联类型推断:当myClass被推断为Class1 | Class2联合类型时,args会被推断为Class1Arg[] | Class2Arg[],但TypeScript无法将两者的类型一一绑定,导致调用methodWithArgs时认为参数类型不匹配。

修复方案

以下方案均能保留工厂模式的灵活性,同时保障类型安全:

方案一:类型守卫缩小范围(简单直接)

通过判断key的值,明确当前实例的具体类型,让TypeScript关联对应参数类型:

async function test() {
  const key = await getFactoryKey()
  const myClass = factory(key)
  const args = await myClass.getArgsArray()
  
  if (key === "class1") {
    (myClass as Class1).methodWithArgs(args as Class1Arg[])
  } else {
    (myClass as Class2).methodWithArgs(args as Class2Arg[])
  }
}

方案二:泛型函数封装关联逻辑(优雅安全)

将实例创建、参数获取与方法调用封装到单一泛型函数中,让TypeScript在固定泛型上下文里完成类型推断:

// 封装关联逻辑的泛型函数
async function handleInstance<K extends keyof typeof classes>(key: K) {
  const myClass = factory(key)
  const args = await myClass.getArgsArray()
  myClass.methodWithArgs(args) // 类型完全匹配,无报错
}

async function test() {
  const key = await getFactoryKey()
  await handleInstance(key)
}

此方案的核心是:泛型K在handleInstance中被固定为单一键类型(而非联合类型),TypeScript能准确关联myClass与args的对应类型。

方案三:优化工厂函数类型定义(进阶)

通过定义关联泛型参数的构造函数类型,强化工厂函数的类型约束:

// 定义构造函数类型,关联泛型参数与方法类型
type BaseClassConstructor<TArg> = new () => BaseClass<TArg> & {
  methodWithArgs(args: TArg[]): unknown
}

// 明确classes的类型
const classes: Record<string, BaseClassConstructor<any>> = {
  class1: Class1,
  class2: Class2
}

// 工厂函数类型保持不变
function factory<K extends keyof typeof classes>(
  key: K
): InstanceType<typeof classes[K]> {
  const TransformerClass = classes[key]
  return new TransformerClass() as InstanceType<typeof classes[K]>
}

// 配合方案二的封装函数使用,类型安全更完善

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 05:13:10