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

Type x is not assignable to {conditional return type y} #28917

Closed
anurbol opened this issue Dec 8, 2018 · 7 comments
Closed

Type x is not assignable to {conditional return type y} #28917

anurbol opened this issue Dec 8, 2018 · 7 comments
Labels
Duplicate An existing issue was already created

Comments

@anurbol
Copy link

anurbol commented Dec 8, 2018

Hello, TS team. I bet this is easy one for you. And I 95% sure it's not a bug (then what?). The code is not entirely mine, but still I wonder why it fails to compile and why TS doesn't break down the error as it usually does.

TypeScript Version: 3.3.0-dev.20181207 (3.1.6 gives the same result, as does the current playground)

Search Terms: "Type x is not assignable to {conditional return type y}"

Code

const fn = <D extends string | undefined>(someParam: string, defaultValue?: D) : D extends undefined ? string | undefined : string => {

  const result = '';

  return result;
}

Expected behavior:
To compile or at least to break down the error.

Actual behavior:
Fails and shows a not very useful error "Type '""' is not assignable to type 'D extends undefined ? string : string'."

Playground Link:
the playground

Is it at all OK to use a conditional type as a return type? Am I missing something?

P.S. This problem came from stackoverflow, I've tried to answer.

@jack-williams
Copy link
Collaborator

jack-williams commented Dec 8, 2018

There are two things going on here: one is an issue with the code; one is a design limitation or bug.

First issue: the conditional type in the return type is distributive, meaning that it will short circuit when D is instantiated to never. As a consequence it is not always correct to return a string, the function might be expected to return nothing. Example:

const fn = <D extends string | undefined>(someParam: string, defaultValue?: D) : D extends undefined ? string | undefined : string => {
  const result = '';
  return result as any; // turn off error
}

// x claims to be never, or nothing, but will be some string
const x: never = fn<never>("a string");

To turn off distribution you want to use 1-tuples:

const fn = <D extends string | undefined>(someParam: string, defaultValue?: D) : [D] extends [string] ? string : (string | undefined) => {
  const result = '';
  return result as any; // turn off error
}

// error: string not assignable to never
const x: never = fn<never>("a string");

The second issue: even when you handle the never case this is still an error because the type checker is missing the corresponding assignability rule. This is tracked by this issue: #26933. I think there is an open PR fixing the problem here: #27932.

@anurbol
Copy link
Author

anurbol commented Dec 8, 2018

@jack-williams I feel that's a great explanation, but due to the lack of English knowledge, failed to comprehend things like "short correct" and Google Translate doesn't help 😄 Maybe as a result I didn't understand what never has to deal with this. The links to the issues do definitely help, though, thank you!

@anurbol
Copy link
Author

anurbol commented Dec 8, 2018

If this issue can be considered as a duplicate by TS team (I am not 100% sure if it is), then I am not against closing it.

@jack-williams
Copy link
Collaborator

@anurbol It was my English that failed here, not yours! Sorry.

It should read short circuit. Basically when D is never the conditional type evaluates to never independent of the condition or branches.

@Nathan-Fenner
Copy link
Contributor

The following type will do what you wanted:

const fn = <D extends string | undefined>(someParam: string, defaultValue?: D) : string | (D extends undefined ? undefined : never) => {

  const result = '';
  return result;
}

The trick is to pull the string | ... out of the conditional, so that it is always an option.

(depending on where your typings are coming from, this may not actually solve your problem).

@weswigham weswigham added the Duplicate An existing issue was already created label Dec 10, 2018
@weswigham
Copy link
Member

Duplicate of #26933

@typescript-bot
Copy link
Collaborator

This issue has been marked as a duplicate and has seen no activity in the last day. It has been closed automatic house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created
Projects
None yet
Development

No branches or pull requests

5 participants