TypeScript使用infer与typeof实现工厂模式相关类型疑问咨询
问题1:infer与构造函数类型相关疑问
这个类型是TS中典型的「条件类型+类型推断」用法,作用是从构造函数类型中提取对应实例的类型,和TS内置的InstanceType工具类型逻辑完全一致,拆分解释各部分含义:
T extends new () => infer R是条件判断逻辑:判断传入的泛型T是不是无参构造函数new () => xxx是TS中构造函数的固定类型写法:new标记该类型可以被new关键字调用,括号内是构造参数的类型定义,箭头后面是new执行后返回的实例类型infer R的作用是让TS自动捕获该构造函数返回的实例类型,存入类型变量R中。infer只能在条件类型的extends子句中使用,专门用于类型运算时动态提取未知的目标类型
- 整个三元表达式逻辑:如果
T是合法的无参构造函数,就返回它的实例类型R,否则返回never标记入参类型不合法
举个实际示例:
class Truck {} // 传入的T是Truck类本身的类型(不是实例类型) type TruckInstance = ExtractInstanceType<typeof Truck> // 最终TruckInstance的类型就是Truck,即new Truck()返回的实例类型
问题2:联合类型作为索引签名的疑问
TS的类型运算和JS运行时逻辑是完全独立的两套规则:JS中传单个键取单个值是运行时行为,而这里的typeof userMap[Keys]是类型层面的索引访问运算,规则如下:
当用联合类型作为索引访问对象类型时,TS会自动遍历联合类型的每一个成员,分别取对应的值类型,最终把所有结果拼成新的联合类型返回。
对应你给出的代码举示例:
// 假设userMap的运行时结构如下 const userMap = { dev: Developer, manager: Manager } // typeof userMap拿到该对象的类型:{ dev: typeof Developer, manager: typeof Manager } // keyof 取该对象所有键的字面量联合类型:'dev' | 'manager' type Keys = keyof typeof userMap; // 用联合类型Keys做索引访问,等价于取每个键对应值类型的联合 // 即 typeof userMap['dev'] | typeof userMap['manager'] // 最终结果就是 typeof Developer | typeof Manager type userTypes = typeof userMap[Keys];
这个特性非常常用,比如要提取某个对象所有值的类型联合,直接写typeof Obj[keyof typeof Obj]即可,无需手动枚举。
MyCloner类实现参考
符合你需求的可直接运行的实现如下,类型推断完全匹配预期:
interface IClonable { clone(): IClonable; color: string; } // 实现Truck类满足IClonable接口 interface TruckOptions { color: string; fuel: string; } class Truck implements IClonable { color: string; fuel: string; constructor(options: TruckOptions) { this.color = options.color; this.fuel = options.fuel; } clone(): Truck { return new Truck({ color: this.color, fuel: this.fuel }); } } class MyCloner { // 泛型约束保证入参必须实现IClonable,返回值自动推断为对应实例的数组 cloneWithRandomColors<T extends IClonable>(source: T, count: number): T[] { const result: T[] = []; const colorPool = ['red', 'blue', 'green', 'yellow', 'black', 'white']; for (let i = 0; i < count; i++) { const cloned = source.clone() as T; cloned.color = colorPool[Math.floor(Math.random() * colorPool.length)]; result.push(cloned); } return result; } } // 调用方式和你要求的完全一致 const vehicleCloner = new MyCloner(); const truck = new Truck({color: 'red', fuel: 'electric'}); const myTenElectricTrucks = vehicleCloner.cloneWithRandomColors(truck, 10); // 自动推断myTenElectricTrucks类型为Truck[]
内容的提问来源于stack exchange,提问作者JC1700
相关产品推荐
相关产品推荐

