I am trying to describe a property that holds event listeners. The listeners are called with the object firing the event as first argument. When I try to pass "this" as a Generic argument to the events interface. I get the error: " Argument of type 'typeof Child' is not assignable to parameter of type 'typeof Base'"
interface BaseEvents<me extends Base> {
render: (me:me) => void
}
class Base {
public listeners?:BaseEvents<this>
}
class Child extends Base {
foo() {
}
}
function create<T extends typeof Base>(cls: T) {
return new cls;
};
const c = create(Child);
Full error:
Argument of type 'typeof Child' is not assignable to parameter of type 'typeof Base'.
Construct signature return types 'Child' and 'Base' are incompatible.
The types of 'listeners' are incompatible between these types.
Type 'BaseEvents<Child> | undefined' is not assignable to type 'BaseEvents<Base> | undefined'.
Type 'BaseEvents<Child>' is not assignable to type 'BaseEvents<Base>'.
Property 'foo' is missing in type 'Base' but required in type 'Child'.ts(2345)
Does anybody know how I can avoid this error?
CodePudding user response:
You need to slightly update BaseEvents
interface BaseEvents<Me extends Base> {
render: <T extends Me>(me: T) => void
}
class Base {
public listeners?: BaseEvents<this>
}
class Child extends Base {
foo() { }
}
function create<T extends typeof Base>(cls: T) {
return new cls();
};
const c = create(Child); // ok
This is because Me
in BaseEvents
in in contravariant position. For instance, try to write BaseEvents in this way:
interface BaseEvents<Me extends Base> {
render: Me
}
You will see that there is no more error in const c = create(Child);
CodePudding user response:
interface Type<T> {
new (): T
}
interface BaseEvents<Me extends Base> {
render: (me: Me) => void
}
class Base {
public listeners?: BaseEvents<this>
}
class Child extends Base {
foo() {
}
}
function create<T extends Base>(cls: Type<T>) {
return new cls;
};
const c = create(Child);