So, I've the following interface:
interface DoStuffInterface {
doStuff(value: string | number): string | number;
}
Why when implementing this interface TS doesn't enforce the signature?
class NumberStuff implements DoStuffInterface {
public doStuff(value: number): string | number { // <====== missing: | string
return value;
}
}
class StringStuff implements DoStuffInterface {
public doStuff(value: string): string | number { // <====== missing: | number
return value.toLowerCase();
}
}
This is easily breakable with something like this:
var numberStuff = new NumberStuff();
var stringStuff = new StringStuff();
function run(thing: DoStuffInterface): void {
console.log(thing.doStuff(42));
}
run(numberStuff);
run(stringStuff); // <====== this fails, due to: `42.toLowerCase()`
So, why TS doesn't enforce NumberStuff
& StringStuff
to have the proper signature? If the signature was properly set this would be a compile-time error, instead you get a run-time error.
Am I missing some config flag? Or is it expected behaviour?
CodePudding user response:
TLDR to enable the desired behavior change method to property:
interface DoStuffInterface {
doStuff: (value: string | number) => string | number;
}
For interfaces under strictFunctionTypes function type parameter positions are checked contravariantly (for "function prop") instead of bivariantly (for method)
The stricter checking applies to all function types, except those originating in method or constructor declarations. Methods are excluded specifically to ensure generic classes and interfaces (such as
Array<T>
) continue to mostly relate covariantly.