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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.06 04:30:01