Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Compiler allows narrower method signature than implemented interface #58315

Closed
CComparon opened this issue Apr 25, 2024 · 7 comments
Closed

Compiler allows narrower method signature than implemented interface #58315

CComparon opened this issue Apr 25, 2024 · 7 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@CComparon
Copy link

πŸ”Ž Search Terms

interface implements allows narrower argument type

πŸ•— Version & Regression Information

This is the behavior in every version I tried (4.7.x and 5.4.x)

⏯ Playground Link

https://www.typescriptlang.org/play/?noUnusedLocals=true&noUnusedParameters=true&target=8&jsx=0&useUnknownInCatchVariables=true&noImplicitOverride=true&noFallthroughCasesInSwitch=true&suppressImplicitAnyIndexErrors=false&exactOptionalPropertyTypes=true&ts=5.4.5#code/JYOwLgpgTgZghgYwgAgJLIN4ChnJgCjgC5kQBXAWwCNpkAfZAZzClAHMBKE866AbiwBfLFgQAbOI0bIAwsmAUADmIgUI4aemy4CxUpRpQu+3lEw5cyKBDBkoIZHGQAqZACYBuYcNEB7EMzICCToALykEADusvgcAgj+jL4qAHRivmz4CCkEAKwcADRBOfgARAAsbqUcccgA9HXIvr6KjFhAA

πŸ’» Code

interface I {
  f(a: number | string): number;
}

class C implements I {
  f(a: number): number {
    return a * 2;
  }
}

const c: I = new C();
console.log(c.f(5), c.f("42")); // ouch

πŸ™ Actual behavior

Compiler accepts code

πŸ™‚ Expected behavior

Compiler should reject code with an error stating that the implementation method signature is not assignable to the interface method signature.

Additional information about the issue

No response

@MartinJohns
Copy link
Contributor

This is working as intended and mentioned in the FAQ: https://github.com/microsoft/TypeScript/wiki/FAQ#parameter-arity-variance-is-correct

@CComparon
Copy link
Author

Thank you @MartinJohns for your quick reply.
I'm confused though, as my case is not about difference in arity but rather in the actual type of a positional method argument.
My apologies if I'm still overlooking a by-design behavior.

@nmain
Copy link

nmain commented Apr 25, 2024

That's not quite the right part of that document, see https://github.com/microsoft/TypeScript/wiki/FAQ#:~:text=A%20method%20and%20a%20function%20property%20of%20the%20same%20type%20behave%20differently.

@RyanCavanaugh
Copy link
Member

Rare MartinJohns L πŸ˜…

Anyway I just updated the FAQ with a new entry about method bivariance; see https://github.com/microsoft/TypeScript/wiki/FAQ#why-method-bivariance

@RyanCavanaugh RyanCavanaugh added the Working as Intended The behavior described is the intended behavior; this is not a bug label Apr 25, 2024
@BayanBennett
Copy link

BayanBennett commented Apr 25, 2024

ℹ️ @CComparon it works as you expect if you use the property syntax for class methods

class B {
  f = (a: number) => {}
}

class C { // same result when using an interface
  f = (a: number | string) => {}
}

async function main(): Promise<void> {
  const b: C = new B(); // Error: Type 'B' is not assignable to type 'C'... Type 'string' is not assignable to type 'number'.
  console.log(b.f(5));
  console.log(b.f("5"));
}

TS Playground

@MartinJohns
Copy link
Contributor

@RyanCavanaugh The new FAQ is missing a TOC, that threw me off and made finding things a lot harder.

@CComparon
Copy link
Author

Thanks both for pointing me to the rationale behind this language tradeoff.
Cheers

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug
Projects
None yet
Development

No branches or pull requests

5 participants