Typescript: override a method with lesser arguments don't generate a error

Created on 18 Aug 2018  路  7Comments  路  Source: microsoft/TypeScript

TypeScript Version: 3.0.1 with --strict

class A {
    public m(a:string|null): string {
        return "";
    }
}

class B extends A {
    public m(a:string): string {
        return "";
    }
}

Expected behavior:
Error message

Actual behavior:
No error

B.m override the method A.m so the following code is valid.

let a:A = new B()
a.m(null);

But now B.m is called with null this violates the typing.

Question

Most helpful comment

IIRC that was because the in the wild code that it broke was rather extensive and because we have bad code, this is why we can't have nice things.

All 7 comments

Unsound parameter hierarchies in classes are unfortunately extremely common, so class methods are allowed to have their parameters be subtypes or supertypes of their base class's parameters

according to https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html with --strictFunctionTypes parameter type checking is contravariantly. So subtyping a argument is not allowed anymore.

I use the --strict compiler option

https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-6.html says "The stricter checking applies to all function types, except those originating in method or constructor declarations."

IIRC that was because the in the wild code that it broke was rather extensive and because we have bad code, this is why we can't have nice things.

this is why we can't have nice things

Indeed; the DOM API itself is unsound in this regard unless you're willing to entertain the notion of write-only properties.

With the response from mattmccutchen I was able find the following issues 18654, 22156, 18963

In #18654 @ahejlsberg wrote:

Methods are excluded specifically to ensure generic classes and interfaces (such as Array) continue to mostly relate covariantly. The impact of strictly checking methods would be a much bigger breaking change as a large number of generic types would become invariant
(even so, we may continue to explore this stricter mode).

The above example has nothing to do with generic classes and an error that can easily be made especially with --strictNullChecks. Is it not possible to apply strictlyFunctionTypes checking to simple subclassing and not to generic. This is not a perfect solution, but better than now.

For anyone new to this convo, I put together a playground demonstrating this example.

With --strictFunctionTypes enabled, a function with parameter type <S extends T> is not assignable to a function with parameter type <T>, as expected:

function method(callback: (param: number|string) => boolean): void { }

method(function (param: number) { return true }) // error as expected

But method overloading with the same pattern does not give an error.

class Parent { 
    run(param: number|string): boolean { return true }
}

class Child extends Parent {
    run(param: number): boolean { return true } // no error!
}
Was this page helpful?
0 / 5 - 0 ratings