Reputation: 821
How I should modify generic type parameter U
of areaCalculator
argument of WithArea
function for it to extend the base class of current MixinFactory
instance?
type Constructor<T> = new (...args: any[]) => T;
interface IArea {
readonly area: number;
}
class MixinFactory<T extends Constructor<Shape>> {
constructor(public Superclass: T) {}
WithArea(areaCalculator: <U extends Shape & IArea>(ctx: U) => number) {
return new MixinFactory<T & Constructor<IArea>>(class extends this.Superclass implements IArea {
get area(): number {
return areaCalculator(this);
}
})
}
}
class Shape {}
class RectRaw extends Shape {
constructor(
public x: number,
public y: number,
public w: number,
public h: number) {
super();
}
}
const Rect = new MixinFactory(RectRaw).WithArea(ctx => {
return ctx.w * ctx.h;
}).Superclass;
const rect = new Rect(10, 10, 20, 20);
console.log(rect.area);
Upvotes: 3
Views: 151
Reputation: 51034
Your areaCalculator
function doesn't need to be generic; there is no need for an additional type parameter U
, and this type parameter is not exposed by the method get area(): number
.
The areaCalculator
function only needs to be defined as accepting whatever object the constructor type T
returns, so with the InstanceType
helper, we can extract that and use it directly in the type annotation:
class MixinFactory<T extends Constructor<Shape>> {
constructor(public Superclass: T) {}
WithArea(areaCalculator: (ctx: InstanceType<T> & IArea) => number) {
return new MixinFactory<T & Constructor<IArea>>(class extends this.Superclass implements IArea {
get area(): number {
return areaCalculator(this as InstanceType<T> & IArea);
}
})
}
}
Note that a type assertion this as InstanceType<T> & IArea
is needed because Typescript isn't able to figure out that if a class extends this.Superclass
of type T
then its instances must have type InstanceType<T>
.
Upvotes: 3