Skip to content

Discriminating unions doesn't work as expected along with function literal types #45482

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
pptang opened this issue Aug 17, 2021 · 3 comments
Closed

Comments

@pptang
Copy link

pptang commented Aug 17, 2021

Bug Report

I'm not sure if this is a bug or expected behavior, but I cannot find the corresponding documentation or related issues, if there is a duplicate issue of this, please let me know, thank you!

🔎 Search Terms

  • Discriminating unions
  • function type annotation

🕗 Version & Regression Information

I switched between all versions available in the playground and it seems to be the same behavior.

⏯ Playground Link

Playground link with relevant code

💻 Code

  • Working version
type Loading = {
  state: 'loading';
};

type Loaded = {
  state: 'loaded';
  data: string;
};

type Result = Loading | Loaded;

function workingVersion(): Result {

  // pass
  // return {
  //   state: 'loaded',
  //   data: 'data',
  // }

  // pass
  // return {
  //   state: 'loading',
  // }

  // compile error (as expected)
  return {
    state: 'loading',
    data: 'data',
  }
}
  • Non-working version
type Result = Loading | Loaded;

type FunctionResult = () => Result;

const nonWorkingVersion: FunctionResult = () => {

  // pass
  // return {
  //   state: 'loaded',
  //   data: 'data',
  // }

  // pass
  // return {
  //   state: 'loading',
  // }

  // no compilation error (but I expect to receive compile error)
  return {
    state: 'loading',
    data: 'data',
  }
}

🙁 Actual behavior

For the non-working version example I put above, it doesn't show any compile error even though the returned structure doesn't match any possibility of my discriminated union type Result.

🙂 Expected behavior

I expect the non-working version (which function type annotation is used) should work the same as working version example I put above.

@MartinJohns
Copy link
Contributor

Duplicate of #39635 / #241 and many many many many many more.

@MartinJohns
Copy link
Contributor

Additionally, this behaviour is unrelated to unions.

    type Result = { a: string }
    type GetResult = () => Result

    const getResult: GetResult = () => ({ a: '', b: '' })

No return type is provided for the anonymous function, so it is inferred. In this case it's inferred to be { a: string, b: string }, and the type of the function is () => { a: string, b: string }. When assigning this to the variable the compiler will check if this type is assignable to GetResult, which it is: No properties are missing or incompatible.

You can get the behaviour you want by adding at type annotation to your function:

const getResult: GetResult = (): Result => ({ a: '', b: '' }) // Now an error

@pptang
Copy link
Author

pptang commented Aug 17, 2021

@MartinJohns Thanks for the clear explanation! I'll close this issue accordingly 🙏🏼

@pptang pptang closed this as completed Aug 17, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants