Reputation: 5550
I am getting error "could be instantiated with a different subtype of constraint" when I have some code like this:
class BaseModel {
hello() {
return "HELLO";
}
static yada() {
return "YADA";
}
}
class OtherModel extends BaseModel {
hola() { return "HOLA" }
}
class Factory<
T extends typeof BaseModel,
M extends BaseModel = T["prototype"]
> {
private _modelClass: T;
constructor(modelClass: T) {
this._modelClass = modelClass;
}
build(): M {
return new this._modelClass();
}
echoClassMethod() {
console.log(this._modelClass.prototype.hello);
}
}
new Factory(OtherModel).build();
However, if I change it to the following I get no error:
class Factory<
T extends typeof BaseModel
> {
private _modelClass: T;
constructor(modelClass: T) {
this._modelClass = modelClass;
}
build(): T["prototype"] {
return new this._modelClass();
}
echoClassMethod() {
console.log(this._modelClass.yada);
}
}
// The following now gets the correct Intellisense for OtherModel.
new Factory(OtherModel).build();
If I use InstanceType<T>
instead of T["prototype"]
it doesn't work either.
Could someone explain why? What should I do differently so that we can alias type T["prototype"]
in our function signatures for the Factory
class?
Upvotes: 1
Views: 46
Reputation: 187034
Usually when you get this error you are using too many generic parameters. You don't need generic parameters that are themselves derived solely from one other generic parameter.
M
in M extends BaseModel = T["prototype"]
is not the same as T["prototype"]
. If an interface extends
another interface, that means that it meets the contract for that interface, but it also may have other fields. Typescript doesn't believe that it can guarantee that it can use T
to create an M
because T
is only guaranteed to be a subset of M
and not a whole M
.
Removing the generic parameter fixes it because nothing extends anything else. The class you are instantiating matches T['prototype']
exactly, because they are both derived directly from T
and neither merely extends T
.
Upvotes: 2