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

Contravariance with optional arguments causes runtime errors #59096

Closed
thomasttvo opened this issue Jul 1, 2024 · 5 comments
Closed

Contravariance with optional arguments causes runtime errors #59096

thomasttvo opened this issue Jul 1, 2024 · 5 comments
Labels
Working as Intended The behavior described is the intended behavior; this is not a bug

Comments

@thomasttvo
Copy link

thomasttvo commented Jul 1, 2024

πŸ”Ž Search Terms

contravariance, function types, crash, optional arguments

πŸ•— Version & Regression Information

Not sure, but it may cause runtime crash

⏯ Playground Link

No response

πŸ’» Code

const x = (first: number, second?: number) => {
   // some logic here
}; 
const y: (first: number) => void = x; // ok
const z: (first: number, second: string) => void = y; // ok

z(123, '123'); // TS says ok, but you'll get a runtime issue.

πŸ™ Actual behavior

A function with optional parameters can get assigned to a function variable with less parameters. At first glance this is ok because you'd think x can be called without second, but it will cause issues when that variable gets assigned to a function variable with more parameters.

πŸ™‚ Expected behavior

x should not be assigned to y

Additional information about the issue

No response

@DanielRosenwasser
Copy link
Member

It's not exactly about variance, but yes, optionality and aliasing mix pretty poorly in some contexts, and it comes up with objects too. There isn't much we're planning to do here, it is an intentional trade-off in usability and soundness.

The closest thing I can find in the FAQ is https://github.com/microsoft/TypeScript/wiki/FAQ#why-are-functions-with-fewer-parameters-assignable-to-functions-that-take-more-parameters

@DanielRosenwasser DanielRosenwasser added the Working as Intended The behavior described is the intended behavior; this is not a bug label Jul 1, 2024
@fatcerberus
Copy link

The same tradeoff applies to objects, fwiw - it’s not specific to functions.

  • { foo: string, bar: string } is assignable to { foo: string }
  • … is in turn assignable to { foo: string, bar?: number }
  • …and now .bar is a string even though the types say it’s a number

@thomasttvo
Copy link
Author

I see, thank you both. I see the support is intentional, but this could cause a variable with an unexpected type gets passed around the code base, which lowers confidence in the advertised type of any variable. Is it possible to at least disallow this kind of behavior in strict mode, or perhaps a lint rule so users can optionally turn it on?

@DanielRosenwasser
Copy link
Member

I think the closest thing would be exact types #12936 because it could(?) disallow the case of {| foo: string |} being assignable to {| foo: string, bar?: number |}.

But that doesn't cover the original issue around function parameter lists.

@typescript-bot
Copy link
Collaborator

This issue has been marked as "Working as Intended" and has seen no recent activity. It has been automatically closed for house-keeping purposes.

@typescript-bot typescript-bot closed this as not planned Won't fix, can't repro, duplicate, stale Jul 5, 2024
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

4 participants