TypeScript将类存入Map并支持静态方法访问与动态类型转换
实现方案
核心思路
我们通过类型自动推导+注册中心的方式实现需求,新增子类仅需在注册中心添加条目,无需修改其他逻辑。
完整实现代码
// 1. 定义带泛型的抽象基类,关联getType返回值和子类类型 abstract class Base<T extends string> { abstract getType(): T; static test(): string[] { return []; } } // 2. 定义子类,指定getType返回的字面量类型 class Foo extends Base<'foo'> { foo = '123'; getType(): 'foo' { return "foo"; } static test(): string[] { return ["a", "b", "c"] } } class Bar extends Base<'bar'> { bar = '321'; getType(): 'bar' { return "bar"; } static test(): string[] { return ["a", "b", "c"] } } // 3. 定义类注册中心,新增子类仅需在这里添加条目 const classRegistry = { foo: Foo, bar: Bar } as const; // 4. 自动推导类型,无需手动维护联合类型 type InstanceTypeMap = { [K in keyof typeof classRegistry]: InstanceType<typeof classRegistry[K]> }; type AllSubClass = typeof classRegistry[keyof typeof classRegistry]; type AllSubInstance = InstanceTypeMap[keyof InstanceTypeMap]; // 5. 初始化类型安全的Map const m = new Map<keyof typeof classRegistry, AllSubClass>( Object.entries(classRegistry) as any ); // 6. 通用类型守卫,用于将Base实例转为对应子类类型 function isInstance<T extends keyof typeof classRegistry>( type: T, instance: Base<string> ): instance is InstanceTypeMap[T] { return instance.getType() === type; } // -------------- 功能测试 -------------- // 需求1:遍历调用静态方法 for (const cl of m.values()) { console.log(cl.test()); // 类型安全,无报错 } console.log(m.get('foo')!.test()); // 直接调用静态方法正常 // 需求2:接收Base实例转为对应子类类型 function func(it: Base<string>) { const baseType = it.getType() as keyof typeof classRegistry; if (m.has(baseType)) { const cl = m.get(baseType)!; // 类型转换后可直接访问子类独有属性 if (isInstance(baseType, it)) { if (baseType === 'foo') { console.log(it.foo); // 类型正确,无报错 } if (baseType === 'bar') { console.log(it.bar); // 类型正确,无报错 } console.log(it); } } } const fooInst = new Foo(); func(fooInst);
新增子类的操作步骤
仅需两步:
- 新增子类继承
Base<字面量类型>,实现对应方法 - 在
classRegistry中添加对应key和子类的映射
其他所有逻辑无需修改,类型会自动推导适配。
原报错原因说明
你之前写的const item = it as cl报错,是因为cl是运行时的变量值,TS类型系统在编译阶段无法直接将运行时值作为类型使用,需要通过预定义的类型映射将运行时的key和对应的子类类型关联起来,再通过类型守卫实现安全的类型转换。
内容的提问来源于stack exchange,提问作者zig1375
相关产品推荐
相关产品推荐

