user1059939
user1059939

Reputation: 1715

Declaring function where the parameter is a class, returning an instance of that class?

I am trying to write the TypeScript definition for a library I use. It has a Plugin system that I have no control of other than plugins must extend Plugin. The PluginManager has a function

add(plugin: any, ...parameters: any[]): any;

Where parameter plugin is a Class (Apple.Tree) and returns an instanceof Apple.Tree. Apple.Tree extends Plugin.

Is there any way to make this a generic function and keep the type?

I tried this:

add<T extends Plugin>(plugin: T, ...parameters: any[]): T;

When I try to call it this function though, it says. Argument of type "typeof Apple.Tree" is not assignable to parameter of type "Plugin"

It says a property is missing in the Apple.Tree. However, since Apple.Tree extends Plugin, it is complaining over something which is there. I have a feeling it might have to do with this generic function.

I would appreciate any advice.

Upvotes: 2

Views: 1291

Answers (2)

CodingWithSpike
CodingWithSpike

Reputation: 43728

You can specify that the parameter plugin is a class constructor with this type constraint:

class PlugIn {
}

class TestPlugIn extends PlugIn {
}

class PluginManager {
  add<T extends PlugIn>(plugin: {new(): T; }, ...parameters: any[]): T {
      return new plugin();
  }
}

var manager = new PluginManager();
var plugin = manager.add(TestPlugIn);

The only thing I didn't do here was to apply the passed in parameters to the constructor.


The {new(): T; } syntax is documented here: TypeScript Handbook: Generics if you scroll down to the section titled "Using Class Types in Generics"

Upvotes: 4

David Sherret
David Sherret

Reputation: 106790

I just worked on a similar problem last night. Here's an example that you can apply to your situation:

class Tree extends Plugin {

}

interface ConstructorOf<T> {
    new(...args: any[]): T; // allow for constructors with any amount of parameters
}

function add<T extends Plugin>(plugin: ConstructorOf<T>, ...parameters: any[]) {
    // create a new instance of plugin and pass in the parameters
    return new plugin(...parameters);
}

var tree = add(Tree); // tree is typed as Tree and not typeof Tree

Source

Upvotes: 5

Related Questions