如何在TypeScript中正确定义泛型构造函数类型?
修复依赖注入系统的类型定义问题
问题根源
你的类型错误源于ConstructorUnknown的定义过于严格:它被限定为无参构造函数(Constructor<object, readonly never[]>),但register函数中传入的entityConstructor是带参数的构造函数(参数类型为Instances<InputEntityConstructors>),两者的参数列表类型不兼容,导致无法直接存入Map。
修复方案
重新定义ConstructorUnknown为任意构造函数,允许它接受任意参数类型,这样就能兼容所有需要注册的构造函数。同时调整相关类型,确保整个DI系统的类型安全。
修正后的类型定义
// 通用构造函数接口,支持任意实例类型和参数列表 interface Constructor<Instance extends object, Params extends readonly unknown[]> { new (...args: Params): Instance } // 改为任意构造函数,不再限定无参 type ConstructorUnknown = Constructor<object, readonly unknown[]> type ConstructorsUnknown = readonly ConstructorUnknown[] // 保持Instances类型,从构造函数数组推导实例数组类型 type Instances<Constructors extends ConstructorsUnknown> = { readonly [Index in keyof Constructors]: InstanceType<Constructors[Index]> }
修正后的register函数
const entityConstructorToInputEntityConstructorsMap = new Map<ConstructorUnknown, ConstructorsUnknown>() function register< const Entity extends object, const InputEntityConstructors extends ConstructorsUnknown, >( entityConstructor: Constructor<Entity, Instances<InputEntityConstructors>>, inputEntityConstructors: InputEntityConstructors, ): void { if (entityConstructorToInputEntityConstructorsMap.has(entityConstructor)) { throw new Error(`Entity "${entityConstructor.name}" is already registered`) } entityConstructorToInputEntityConstructorsMap.set(entityConstructor, inputEntityConstructors) }
修复逻辑说明
ConstructorUnknown不再限制参数类型为never[],而是用unknown[]兼容任意参数列表,带参数的构造函数也能匹配该类型。- 泛型约束依然保留,确保
entityConstructor的参数类型严格对应InputEntityConstructors的实例数组,维持类型安全。 - 无需显式类型转换,就能直接将构造函数存入Map,彻底解决原有的类型不兼容错误。
可选优化
如果需要更精确的类型推导,可以将ConstructorUnknown改为泛型默认值,或者用Constructor<any, any>(但unknown比any更安全),上述方案已经能满足大部分DI场景的类型需求。
内容的提问来源于stack exchange,提问作者Parzh
相关产品推荐
相关产品推荐

