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

如何为.reduce返回的类实例对象标注TypeScript正确类型?

TypeScript批量实例化类的类型标注解决方法

需求背景

我有多个需要动态实例化的类,想把它们存在变量里,通过遍历批量创建实例——以后只要往存储结构里加新类,就能自动完成实例化。同时要给最终的实例对象classesInstances标注正确的类型,让每个属性对应对应类的实例。

初始尝试(数组存储类)

一开始用数组存类,代码如下:

// 单独文件中的类导出与存储
import { ClassOne } from '@data/ClassOne';
import { ClassTwo } from '@data/ClassTwo';
 
export const myClasses = [
  ClassOne,
  ClassTwo,
] as const;

// 遍历实例化
const classesInstances = myClasses.reduce((acc, CurClass) => {
  acc[_.camelCase(CurClass.name)] = new CurClass({
    globalOptions,
    sharedCache,
  });
  return acc;
}, {});

但没法给classesInstances标注出{ classOne: ClassOne实例, classTwo: ClassTwo实例 }这样的精准类型,用Record<string, ...>只能得到模糊的联合类型。

改用对象存储类后的进展与问题

后来改用对象存储类,终于能定义出正确的实例类型,但reduce循环内部报错:

// 第一个文件:存储类的对象
import { ClassOne } from '@data/ClassOne';
import { ClassTwo } from '@data/ClassTwo';

export const myClasses = {
  classOne: ClassOne,
  classTwo: ClassTwo,
};

// 第二个文件:定义实例类型
type ClassesInstances = {
  [key in keyof typeof myClasses]: InstanceType<(typeof myClasses)[key]>;
};

// 遍历实例化,但reduce内部报错
const myClassesInstances = Object.entries(myClasses).reduce(
  (acc, [key, MyClass]) => {
    // 报错:类型“ClassesInstances”上不存在类型为“string”的参数的索引签名。
    acc[key] = new MyClass({
      context,
      cache,
    });
    return acc;
  },
  {} as ClassesInstances,
);

// 注:myClassesInstances的最终类型是正确的,只是reduce内部有报错

尝试把key断言为keyof ClassesInstances后,又出现新报错:Type 'ClassOne | ClassTwo' is not assignable to type 'ClassOne & ClassTwo'.

解决方法

问题根源是Object.entries会把键的类型推断为string,TypeScript没法跟踪每个键对应的具体类。下面是三种可行的解决方式:

方式1:精准类型断言

在reduce内部给key和实例做精准的类型断言,确保类型匹配:

const myClassesInstances = Object.entries(myClasses).reduce(
  (acc, [key, MyClass]) => {
    const typedKey = key as keyof typeof myClasses;
    acc[typedKey] = new MyClass({ context, cache }) as InstanceType<(typeof myClasses)[typeof typedKey]>;
    return acc;
  },
  {} as ClassesInstances,
);

方式2:改用for...in循环

for...in能更好地保留键的类型信息,避免Object.entries的类型丢失问题:

const myClassesInstances: ClassesInstances = {} as ClassesInstances;
for (const key in myClasses) {
  if (myClasses.hasOwnProperty(key)) {
    myClassesInstances[key] = new myClasses[key]({ context, cache });
  }
}

方式3:封装泛型工具函数

如果需要复用逻辑,可以写一个泛型函数自动推导类型,不用手动定义ClassesInstances:

function instantiateClasses<T extends Record<string, new (...args: any[]) => any>>(
  classes: T,
  instanceArgs: ConstructorParameters<T[keyof T]>[0]
): { [K in keyof T]: InstanceType<T[K]> } {
  const instances = {} as { [K in keyof T]: InstanceType<T[K]> };
  for (const key in classes) {
    instances[key] = new classes[key](instanceArgs);
  }
  return instances;
}

// 使用时直接传类对象和实例参数,自动推导类型
const myClassesInstances = instantiateClasses(myClasses, { context, cache });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 19:18:31