高级 Typescript 推理

Advanced Typescript inference

我目前正在尝试构建一个插件库。这些插件有一些共同的方法,而另一些则完全不同。

示例:

class PluginA extends Plugin {
  specificAMethod() {
    ....
  }
}

class PluginB extends Plugin {
  specificBMethod() {
    ....
  }
}

我想做的是有一个像这样的插件注册表:

const pluginRegistry: Record<string, Plugin> = {
 a: PluginA,
 b: PluginB
}

问题在于,如果我尝试执行 a.specificAMethod(),我将得到错误 method specificAMethod does not exist on type Plugin

因为这是一个库,我希望它是自动的,这样当用户导入插件时,它会自动拥有正确的类型而不是 (a as PluginA).specificAMethod()

我也试过联合类型而不是继承,但同样的问题。

我也知道只要这样做就可以逃脱:

const pluginRegistry = {
  a: PluginA,
  b: PluginB
}

但我不喜欢它,因为它在公开库时有效,但我实际上想要一个我可以重用的类型,因为我需要它用于其他抽象案例,而且这种方式也更有趣。

有没有办法让 TypeScript 自动正确推断每个插件的类型?

I also know that i can get away with it with just doing :

const pluginRegistry = {
    a: PluginA,
    b: PluginB
}

But i don't like it since it works when exposing the library but i actually want to have a type that i can reuse because i need it for other abstract cases...

这不是问题,只需从对象中获取类型即可:

const pluginRegistry = {
    a: PluginA,
    b: PluginB
} as const;
export type PluginRegistry = typeof pluginRegistry;
//          ^? −−−− type is { readonly a: typeof PluginA, readonly b: typeof PluginB };

Playground link

...and it is also more interesting this way

如果您不想这样做,则必须使用明确的键和类型编写您的类型:

export type PluginRegistry = {
    // `readonly` is optional, depends on your use case
    readonly a: typeof PluginA;
    readonly b: typeof PluginB;
};

const pluginRegistry: PluginRegistry = {
    a: PluginA,
    b: PluginB,
};

...因为 Record<string, Plugin> 将相当广泛。

Playground link