Reputation: 1715
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
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
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
Upvotes: 5