Reputation: 7620
I am following this exemple =>
Typescript: How to extend two classes?
In My case, I want to extend a main class =>
export class MyClassOne {
constructor(param1, param2)
}
and
MyClassTwo<F extends interface1, O extends interface2>{
constructor(param3, param4)
}
So I tried the following
const addMyClassOneInheritance = (MyClassOne : { new(...args) }) => {
return class extends MyClassOne {};
}
const MyFinalClass = addMyClassOneInheritance(MyClassTwo);
export class SynchMapComponent extends MyFinalClass{
it works but I don't know a way to set my generic types. because if I had anything within the <> I get an error
Value of type 'typeof MyClassTwo' is not callable. Did you mean to include 'new'?
Upvotes: 1
Views: 7172
Reputation: 1636
While mixins are a really great concept in general, I feel they don't really address the issue of extending two classes in a single one. Rather they enhance one class with a fixed set of extra functionality. Actually I don't think it's possible to extend two different, unrelated classes in a single one. But assuming we accept two minor accomodations we can get pretty close:
instanceof
one of its anchestors (let's say the first).class
extending two others in a generic way. We'll settle for a factory function instead.Now, take a look at the following function:
type Constructable = new (...args: any[]) => any;
const mergeClasses = <S extends Constructable, T extends Constructable>(class1: S, class2: T) =>
<Si extends InstanceType<S> = InstanceType<S>, Ti extends InstanceType<T> = InstanceType<T>>
(args1: ConstructorParameters<S>, args2: ConstructorParameters<T>): Si & Ti => {
const obj1 = new class1(...args1);
const obj2 = new class2(...args2);
for (const p in obj2) {
obj1[p] = obj2[p];
}
return obj1 as Si & Ti;
};
Calling it will return a factory function that constructs object instances implementing both classes originally passed to mergeClasses
. For example to extend two classes
class MyClassOne {
constructor(param1: number, param2: number) { }
}
class MyClassTwo<F, O> {
constructor(param3: number, param4: number) { }
}
you'd just write the following (omit the type parameters if they're not generic):
const instanceFactory = mergeClasses(MyClassOne, MyClassTwo);
const instance = instanceFactory<MyClassOne, MyClassTwo<number, string>>([1, 2], [3, 4]);
You can also check out the sample code here.
Upvotes: 2
Reputation: 250056
You need to use generics to make sure the type of the original class is forwarded to the output of the function. This pattern is outlined here.
This code will work as expected keeping all type parameters in the output
const addMyClassOneInheritance = <T extends new(...args: any[]) => any>(MyClassOne: T)=> {
return class extends MyClassOne { };
}
class MyClassTwo<F extends string, O extends number>{
constructor(param3: F, param4: O) { }
}
const MyFinalClass = addMyClassOneInheritance(MyClassTwo);
export class SynchMapComponent extends MyFinalClass<string, number> {
}
new SynchMapComponent("", 1)
Upvotes: 1
Reputation: 793
This is a simple example for extending a generic class and same way you can do multiple extends with generic type and even how you can initialize or create instance:
class BeeKeeper {
hasMask: boolean;
}
class ZooKeeper {
nametag: string;
}
class Animal {
numLegs: number;
}
class Bee extends Animal {
keeper: BeeKeeper;
}
class Lion extends Animal {
keeper: ZooKeeper;
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag; // typechecks!
createInstance(Bee).keeper.hasMask; // typechecks!
Upvotes: 1