TypeScript实现带参数工厂模式时类型报错如何解决?
问题分析
第一个create函数报错原因
你理解的FactoryMap[T]是A | B没错,但目前TypeScript无法对「泛型参数T和返回值FactoryMap[T]」的关联类型做缩小推断。你在switch分支里判断了name === "A",你自己知道此时T就是字面量类型A,返回值应该对应FactoryMap["A"]也就是A,但TS做不到这个关联推导,它只会把分支里的返回值和全局的FactoryMap[T]做交叉校验,也就是要求返回值同时满足所有FactoryMap的value类型,自然就会报A不能赋值给A & B的错误。
第二个create2函数报错原因
首先是返回值类型写错了:typeof map[T]是类本身的类型(比如typeof A),而你new map[name](...)返回的是类的实例类型,应该用InstanceType<typeof map[T]>才对。改了返回值类型之后还是会有报错,本质和第一个函数的问题一样,是TS无法关联泛型T和实例类型的推导。
解决方法
方案1:类型断言(最简单快速)
对于这种你100%确定逻辑正确,只是TS推导能力不足的场景,直接用as做类型断言即可,两种函数都可以用这个方法解决:
class A { constructor(public name: string) {} } class B { constructor(public age: number, public address: string) {} } const map = { A, B } // 修复后的create2,更简洁不需要额外定义FactoryMap function create2<T extends keyof typeof map>(name: T, ...params: ConstructorParameters<typeof map[T]>): InstanceType<typeof map[T]> { return new map[name](...params) as InstanceType<typeof map[T]>; } // 测试调用,类型完全正确 const a = create2("A", "测试"); // a是A类型 const b = create2("B", 18, "北京"); // b是B类型
方案2:函数重载(更严谨,适合对外暴露的公共方法)
如果不想用类型断言,可以用函数重载来定义不同入参对应的返回类型,TS会优先匹配重载签名:
type FactoryMap = typeof map; function create<T extends keyof FactoryMap>(name: T, ...params: ConstructorParameters<FactoryMap[T]>): InstanceType<FactoryMap[T]> function create(name: keyof FactoryMap, ...params: any[]) { return new map[name](...params); }
这个写法完全没有类型断言,也不会有报错,调用时的类型提示也完全正确。
内容的提问来源于stack exchange,提问作者crazyones110
相关产品推荐
相关产品推荐

