Skip to content

undefined is acting like any in generics extension checks #49862

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

Closed
ghost opened this issue Jul 11, 2022 · 5 comments
Closed

undefined is acting like any in generics extension checks #49862

ghost opened this issue Jul 11, 2022 · 5 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@ghost
Copy link

ghost commented Jul 11, 2022

Bug Report

πŸ”Ž Search Terms

generic function call

πŸ•— Version & Regression Information

  • This is the behavior in every version I tried, and I reviewed the FAQ for entries about generics

⏯ Playground Link

playground link

πŸ’» Code

type IfAny<T> = 0 extends (1 & T) ? true : never

declare function bool<T extends IfAny<T>>(value?: T): 'caught';
declare function bool<T>(value?: T): 'not caught';

declare function bool2<T extends {['gibberish']: T}>(value?: T): 'caught';
declare function bool2<T>(value?: T): 'not caught';

const A = bool(undefined);  // caught ???
const B = bool2(undefined); // caught ???
const C = bool();           // caught ???
const D = bool2();          // caught ???

πŸ™ Actual behavior

both implicit and explicit undefined arguments seems to act like any when used in a generic when the argument is optional. This behavior is not seen when the argument is required

πŸ™‚ Expected behavior

undefined shouldn't extend everything

@MartinJohns
Copy link
Contributor

MartinJohns commented Jul 11, 2022

Your function argument value is typed T | undefined because it's an optional parameter. So when you call it passing undefined or without an argument, there's nothing to infer T from, so T resolves to never, and never extends every type.

@ConnorJamesLow
Copy link

That's expected. See Everyday Types and More on Functions from the handbook.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Jul 11, 2022
@ghost
Copy link
Author

ghost commented Jul 11, 2022

never extends every type.

This seems incredibly strange! What's the logic here?

@fatcerberus
Copy link

fatcerberus commented Jul 11, 2022

never is the bottom type which is the opposite of the top type unknown. It conceptually represents the result of operations that never complete (a function that throws, e.g.), so you can treat it as any type you want. In set-theoretical terms, never is an empty set (because there are no values of that type)--which is a subset of every other set.

Since you asked for logical justification πŸ€“, the relevant logical concept is the principle of explosion - you can prove anything from a contradiction. From the point of view of the code holding a value of type never, anything can be "proven" (computed) from it because taking a value from a set with no values is a logical contradiction. In type systems, this usually manifests as the bottom type being the universal subtype, just as unknown is the universal supertype.

@ghost
Copy link
Author

ghost commented Jul 11, 2022

Thanks for the thorough explanation!!

This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Question An issue which isn't directly actionable in code
Projects
None yet
Development

No branches or pull requests

4 participants