1

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 ?

1 Answer 1

2

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 };

Playground link

...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.

Playground link

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.