I am currently trying to build a plugin library. These plugins have some methods in common, and others that are really different.
Example :
class PluginA extends Plugin {
specificAMethod() {
....
}
}
class PluginB extends Plugin {
specificBMethod() {
....
}
}
What I want to do, is have a plugin registry that goes something like this :
const pluginRegistry: Record<string, Plugin> = {
a: PluginA,
b: PluginB
}
The problem with this, is that if I try to do a.specificAMethod()
I will get the error method specificAMethod does not exist on type Plugin
.
And since this is a lib, I want it to be automatic, so that when the users imports a Plugin, it automatically has the right type instead of doing (a as PluginA).specificAMethod()
.
I also tried union types instead of inheritance, but same problem.
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 and it is also more interesting this way.
Is there a way that I can get TypeScript to correctly infer the type of each plugin automatically ?
CodePudding user response:
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...
That's not a problem, just get the type from the object:
const pluginRegistry = {
a: PluginA,
b: PluginB
} as const;
export type PluginRegistry = typeof pluginRegistry;
// ^? −−−− type is { readonly a: typeof PluginA, readonly b: typeof PluginB };
...and it is also more interesting this way
If you don't want to do that, you'll have to write your type with explicit keys and types for them:
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,
};
...since Record<string, Plugin>
will be quite broad.