gr2m / javascript-plugin-architecture-with-typescript-definitions

Plugin architecture example with full TypeScript support

Repository from Github https://github.comgr2m/javascript-plugin-architecture-with-typescript-definitionsRepository from Github https://github.comgr2m/javascript-plugin-architecture-with-typescript-definitions

Typing cross plugin communication

jpbourgeon opened this issue · comments

Hello

In my setup, a plugin A adds a method and/or property to the base. Then a plugin B calls the method and accesses the property. It works fine.

However I have no clue of how I should type my code to let typescript know that, at execution time, plugin B will have access to the ressources provided by plugin A...

I understand that I need to "augment" the Base type with the properties that pluginA adds on top of it, but I have no clue how I should actually do that.

Could you help me type this out or suggest another pattern to avoid this problem?

function pluginA() {
  const result : { property?: number, method: () => void } = {
    property: "",
    method: () => undefined
  };
}

function pluginB(base:Base) {
  base.property = 1; // the type checker throws : 'property' doesn't exist on type 'Base<Options>'.ts(2339)
  base.method(); // the type checker throws : 'method' doesn't exist on type 'Base<Options>'.ts(2339)
}

// However everything works fine at runtime since the plugins have been added in the right order:

const MyBase = Base.withPlugins([pluginA, pluginB]).withDefaults({});
const instance = new MyBase();
console.log(instance.property);
instance.method();

P.S. : the actual case is an event emitter plugin which props are consumed by various microservices plugins to communicate with each other.

I avoid that use case in Octokit. Instead I make plugins composable. Besides exporting the plugin functions (pluginA(), plubinB()), I also export composePluginA()/composePluginB(). The compose* functions take an instance as their first argument.

So in your case, it would look like this

import { composePluginA } from "plugin-a"

function pluginB(base:Base, options) {
  composePluginA(base, options)
}

For example see the composePaginateRest function exported by https://github.com/octokit/plugin-paginate-rest.js#readme

Thanks for the hint !