If your creating a plugin system, Typescript has a nice feature called interfaces, you could also use classes, but it's not required.
So for a simply example let's create a simple plugin that simply has a hello method.
First we need to create some sort of plugin manager, here we can store the expected interface the plugin will need, and also some place to register said plugin.
//plugin.ts
interface MyPlugin {
hello: () => void
}
interface Settings {
plugin?: MyPlugin
}
export const settings:Settings = {
}
export function plugin() {
if (!settings.plugin)
throw new Error('No plugin registered');
return settings.plugin;
}
Nothing too complicated here, we have a simple interface that our plugins will need to implement, a settings structure to store the current plugin. And a simple utility function to get the current plugin and throw an error if one not yet registered.
For demo purposes I'm just using separate files, but these files could be in different NPM repo's, Javascript doesn't care..
So next, let's create our first plugin.
//plugin-a.ts
import {settings} from "./plugin";
settings.plugin = {
hello: () => console.log('plugin A');
}
We can do the same for our next plugin.
//plugin-b.ts
import {settings} from "./plugin";
settings.plugin = {
hello: () => console.log('Another plugin B');
}
Finally let's use our plugins.
import "./plugin-a";
import {plugin} from "./plugin";
plugin().hello();
In the above if we change the ./plugin-a to ./plugin-b, everything will just work with the new plugin.
You could now easily extend your plugin later to have a bye method and Typescript is going to automatically let you know what needs implementing in plugin-a & plugin-b.
Of course this is a very simple plugin system, you might have a plugin system were you can register multiple plugins, here an array of plugins could be kept. To clean things up, it might also be an idea to have a register function instead of using settings.plugin = etc. But I've deliberately kept this as simple as possible for people to follow.