Skip to content

Compile does not produce an error when parameters in overriding class method in child class have narrower type than the parameters of this method in the parent class #58122

Closed as not planned

Description

🔎 Search Terms

[class ](is:issue is:open label:Bug inherit)

🕗 Version & Regression Information

  • This is a crash
  • This changed between versions ______ and _______
  • This changed in commit or PR _______
  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about strictFunctionTypes here
  • I was unable to test this on prior versions because _______

⏯ Playground Link

https://www.typescriptlang.org/play?#code/PTAEBUAsFNQYwPYBNYCNoBsEHdQEsBneBAWwAc8NolRs8AXSBAV3tGgCcOEP2A3aADtaDSKAC04gvQ5449AGLNB8vAkHgAnmWgEAUCFABDDIxYBzMQ1BluSZnF3Hhnbr2yRKaaHkHn2AB7QcKzUenq+9JwAZkaOoACSoADeeqDpxgBcoILMJOgcANx6AL7hkTFxsABSgVGCSERJqRmgqNnSsn7FZXpwGEYERACCKWkZZMyoGHKgJAAUAdkJAJTZufmcY62tHND0zBzCAQB0RsWtJT3h-YNEAEJ1Qo2go6nj6YZQhKAIAlx4FBEEj7Jg0ABEJHB+GEtyGoHBw3BJw+oEMAGUHGI-q5AbASMxpG1YNEeKhAShBAAaVGGdBwIyE2DWQRGLg4IhIHDCRiwMhsowgqK8ejaWAIaJzUHIBFQ4jkNnUUD0BA2RWCNhwgg01qGDxyMQMplEIwudnuGDCBCoABWwTYEvgA3h4Pu0J+TJovmk0CMNEd1rt8l+kq1CKRKNak2mswWS1A1TWOTyBW2O3SewOR1ApyMoAA1DmTqgTlQ-IwLhkrqVwtFlKp1KBootssMkxtUy0MohBESyMtQABeFJGbIARmru32h2OJwWZBW1z66iJ7VAj2HgmguHu80X4UMShU9DUwnB0WhcUcZHoJo45jyQgdoedRFdl4wBFV9MZBFg7-wE1QAIKYw0dRFwRpOlWHwNhbGQBwnHBABhU1BAQNg9j9GxuB0DgTycR1lBQaJfCVeYsKQXx-AAcjLcxGBolZwWXXs2HjDstmHZtUEXIA

💻 Code

// The code below is compiled without error even with --strictFunctionTypes
// although it produces an error while being executed

interface I {
    a: number;
}

interface J extends I {
    b: string;
}

class A {
    public m(x: I): number {
        return x.a;
    };
}

class B extends A {

    // This overrides method "m" in class "A".
    // Such override must be forbidden,
    // because it narrows down the parameter type of method "m" compared to parent class,
    // which causes an error when object of class "B" is used instead of object of class "A".
    public m(x: J): number {
        return x.a + x.b.length;
    };
}

function f(x: A): number {
    const p: I = {a: 1};
    return x.m(p);
}

const b: B = new B();

// Function "f" accepts argument of class "B" also because "B" is a subclass of "A",
// but it produces "Cannot read properties of undefined (reading 'length')"
const x: number = f(b);

🙁 Actual behavior

The code above is compiled without an error even with --strictFunctionTypes, but when executed it gives Cannot read properties of undefined (reading 'length') error. Bug here is that TypeScript compiler does not recognize an error in the code above.

🙂 Expected behavior

I expect that code above should produce a compilation error (see additional information below).

Additional information about the issue

Below is the similar code, but if compiled with --strictFunctionTypes TypeScript gives an error, which is expected. The difference of the code below from the code above is that in the above code m is a method of classes, but in the code below m is a member of classes.

// The code below has compilation error with --strictFunctionTypes
// and has no compilation error without --strictFunctionTypes
// This is expected behaviour.
//
// Error witht --strictFunctionTypes:
// Property 'm' in type 'B' is not assignable to the same property in base type 'A'.
//   Type '(x: J) => number' is not assignable to type '(x: I) => number'.
//     Types of parameters 'x' and 'x' are incompatible.
//       Property 'b' is missing in type 'I' but required in type 'J'.

interface I {
    a: number;
}

interface J extends I {
    b: string;
}

class A {
    public m = (x: I) => {
        return x.a;
    };
}

class B extends A {
    public m = (x: J) => { // <-- here is a compilation error
        return x.a + x.b.length;
    };
}

I wonder why --strictFunctionTypes enables contravariance for function parameters, but not covariance? This doesn't seem logical, because as it was shown above it allows a runtime error which could be caught at compile time.

Activity

  1. MartinJohns commented on Apr 8, 2024

    @MartinJohns
    Contributor

    This is working as intended. There's even a section in the FAQ about this, and the behavior is required for some types (e.g. Arrays). Note that strictFunctionTypes applies to functions, not methods.

  2. edrennikov commented on Apr 8, 2024

    @edrennikov
    Author

    But as provided in the example above there is obviously an error in the code which can be caught at compile time.

  3. MartinJohns commented on Apr 8, 2024

    @MartinJohns
    Contributor

    Yes, that's true. But it's still working as intended. TypeScripts type system is not fully sound (and it's not intended to).

    Your intended change would break a whole lot of other stuff. See also #57783 for more information.

  4. edrennikov commented on Apr 8, 2024

    @edrennikov
    Author

    TypeScripts type system is not fully sound (and it's not intended to)

    That's sad 😕 Another broken dream in software development 🥲

  5. locked as resolved and limited conversation to collaborators on Oct 22, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions