Plugin-augmented interface

34 Views Asked by At

I am working on a "manager" class which allows/enables "plugins". Each plugin will (optionally) augment a data member of the manager class.

// manager.ts
interface Data {
    // some props
}

class Manager {
    data: Data;
    // TSC Problem: "Property 'data' has no initializer and is not definitely assigned in the constructor."

    constructor() {
        // can not set all possible properties of this.data because
        // the Manager class doesn't know what all will be plugged in
    }
}

Plugins get a reference to the class instance they are plugging into. They may also augment the interface of Data to better define the data object?

// plugins/A.ts
interface Data {
    // additional props
}

function A(boss: Manager) {
    // "A" adds data to boss.data that is unique to "A"
}

These are my questions I think:

  1. Is this a good pattern?
  2. Is this the way to accomplish this, or is there a better way?

I read about Declaration Merging (https://www.typescriptlang.org/docs/handbook/declaration-merging.html) and that sounds like the best option in my case because there will be many Plugins that are all independant and Discriminated Unions (https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) would likely be out of the question pretty immediately.

EDIT: Maybe my question isn't clear; Is it possible to use declaration merging across multiple files?

2

There are 2 best solutions below

0
kalisjoshua On BEST ANSWER

I just figured this out.

// Manager.ts
interface Data {
    // some props maybe
}

class Manager {
    data: Data;
    // TSC Problem: "Property 'data' has no initializer and is not definitely assigned in the constructor."

    constructor() {
        // can not set all possible properties of this.data because
        // the Manager class doesn't know what all will be plugged in
    }
}

// plugins/A.ts
declare module "../Manager" {
  interface Data {
    Scale: number;
  }
}

function A(boss: Manager) {
    // "A" adds data to boss.data that is unique to "A"
}
1
axtck On

You are receiving the error message because you are not assigning a value to the data property while you mark it as type Data. You could set the value through the constructor:

interface Data {
  name: string;
}

class Manager {
  public data: Data;

  constructor(data: Data) {
    this.data = data;
  }
}

And create objects like this:

const boss: Manager = new Manager({ name: "boss" });