Reputation: 6873
Sorry for the weird title, I don't quite know how to describe what I'm trying to do in one sentence.
I have to define a bunch of classes that are all going to extend from this one class and also implement this other class.
class SoulCoughing extends Super implements BonBon { /.../ }
class MoveAside extends Super implements BonBon { /.../ }
class LetTheManGoThru extends Super implements BonBon { /.../ }
I have written a sort of wrapper function that I use as a decorator for these classes.
const Eminem = function(klass: Constructable<????>) {
const instance = new klass();
// Do stuff
}
Constructable
is a little interface I'm using because otherwise TypeScript would throw an error about not having a constructor.
interface Constructable<T> {
new(): T;
}
Now here is my problem, I don't know what type to assign to parameter klass
in my wrapper function? I have tried doing this:
... function(klass: Contrusctable<Super & BonBon>)
and this:
... function(klass: Contrusctable<Super | BonBon>)
I also tried modifying my constructable interface like this:
interface Constructable<T, U> {
new(): T & U;
}
... function(klass: Contrusctable<Super, BonBon>)
but I keep getting an Argument of type 'typeof SoulCoughing' is not assignable to parameter of type 'Constructable<everythingIveTriedSoFar>'
error.
So my question is, what type definition should I use with the parameter klass
? I know I can just use any
but I'd really like to make sure that the class being passed has extended Super
and implemented BonBon
.
Upvotes: 1
Views: 292
Reputation: 328262
I'm going to guess that the classes SoulCoughing
etc. don't actually have no-arg constructors, and therefore cannot act as Constructable<{}>
at all; the most likely culprit is that Super
's constructor has a mandatory argument, which would make all subclasses fail to match new()
by default. Note that this also implies that your implementation of Eminem
probably wants to call new klass(...)
with some arguments also.
The right way to fix it is to declare Constructable<T>
to be a constructor with the right argument types. Let's say Super
looks like this:
class Super {
constructor(elevator: number, mezzanine: string) {
//...
}
}
Then you could define Constructable
to match:
interface Constructable<T extends Super & BonBon = Super & BonBon> {
new(chump: number, change: string): T; // same args as Super
}
and Eminem
like:
const Eminem = function(klass: Constructable) {
const instance = new klass(2, "rise");
// Do stuff
}
and finally:
Eminem(SoulCoughing); // no error
I only kept Constructable
generic in case you wanted TypeScript to preserve the type of the particular subclass, like so:
const SlimShady = function <T extends Super & BonBon>(klass: Constructable<T>): T {
return new klass(2, "fat");
}
// returns same type as passed-in constructor
const cutLean: MoveAside = SlimShady(MoveAside);
Okay, hope that helps; good luck!
Upvotes: 1