Home > other >  Why TypeScript doesn't enforce interface signature?
Why TypeScript doesn't enforce interface signature?

Time:11-03

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?

Here the full example

CodePudding user response:

TLDR to enable the desired behavior change method to property:

interface DoStuffInterface {
    doStuff: (value: string | number) => string | number;
}

Playground


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.

  • Related