Reputation:
Hi guys so I have this problem
I'm creating a service that i only want to use with a constraint
for that I have an interface
abstract class Base {
}
class ModelFromBase extends Base {
}
interface IService<T extends Base> {
doSomething(model: T);
}
and this class that implements the interface
class ModelNotFromBase {
}
class Services<ModelNotFromBase> implements IService<ModelNotFromBase> {
doSomething(model: T) {}
}
The issue is that ModelNotFromBase does not extends Base (as name suggests), and the TS compiler does not scream about it.
Also when I'm creating an IService instance
private _instance: IService<ModelNotFromBase>;
same issue, I mean i could provide anything there.
So what is the issue here,
As the documentation shows you can use constraints
https://www.typescriptlang.org/docs/handbook/generics.html
Is there something that I'm missing out ? or am I not doing it the correct way ?
Upvotes: 1
Views: 634
Reputation: 249476
Depending on how Base
and ModelNotFromBase
are defined, this may be the expected behavior. When determining type compatibility, typescript uses structural compatibility. This means that these two classes are perfectly compatible with one another:
class Base {
name: string;
}
class ModelNotFromBase {
name: string;
}
var b : Base = new ModelNotFromBase(); // Works fine
If the class/interface Base
is empty (class Base { }
), then the constraint, does not really constrain anything as any other type can be assign a variable of this type
class Base { }
var d : Base = 0;
var d2: Base = "";
If you want to avoid structural typing, you can define a private property on the Base
class (it does not have to be used it just has to be present) and then constraint can only be satisfied by a class that inherits Base
:
class Base {
private nonstructural: true;
}
class ModelNotFromBase { }
interface ITemplatingService<T extends Base> {
doSomething(model: T);
}
export class Services<T extends Base> implements ITemplatingService<T> {
doSomething(model: T) { }
}
var _instance: ITemplatingService<ModelNotFromBase>; //error
export class OtherServices implements ITemplatingService<ModelNotFromBase> { // also error
doSomething(model: ModelNotFromBase) { }
}
Upvotes: 1