Skip to content

Conditional type inference gives conflicting results for functions returning booleans #36683

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
vitoke opened this issue Feb 7, 2020 · 2 comments
Labels
Question An issue which isn't directly actionable in code

Comments

@vitoke
Copy link

vitoke commented Feb 7, 2020

TypeScript Version: 3.8.0-dev.20200206

Search Terms:
conditional boolean

Code

type Example1<T> = () => T;
type Example2<T> = T extends any ? () => T : never;
type Example3<T> = T extends never ? never : () => T;

function test1<T>(e: Example1<T>): void {}
function test2<T>(e: Example2<T>): void {}
function test3<T>(e: Example3<T>): void {}

test1(() => 1); // ok
test2(() => 1); // ok
test3(() => 1); // ok

test1(() => ''); // ok
test2(() => ''); // ok
test3(() => ''); // ok

test1(() => true); // ok
test2(() => true); // fail
test3(() => true); // fail

test3(() => false);         // fail
test3(() => true as true);  // ok

// root cause: with boolean, conditional type is inferred to be:
type FalseOrTrueReturn = (() => false) | (() => true)
const falseOrTrueReturn: FalseOrTrueReturn = () => (false as boolean)  // fail

// it only fails for function return type, so this works:
type FalseOrTrueArg = ((value: false) => void) | ((value: true) => void)
const falseOrTrueArg: FalseOrTrueArg = (value: boolean) => {} // ok

Expected behavior:
All failing lines should compile just fine. This is a simplified example, but it prevents correct type inference for more complex real-world use-cases.

Actual behavior:
Compiler fails to compile the lines with a function returning a boolean. This is due to the boolean return value being destructured into () => true | () => false, and () => boolean is not assignable to that.

Playground Link:
TS Playground

Related Issues:
Possibly:
#33369
#35861

@weswigham
Copy link
Member

weswigham commented Feb 7, 2020

@vitoke you probably want to write

type Example2<T> = [T] extends any ? () => [T] : never;

conditionals by default distribute their computation over unions, and boolean is a union of true | false.

@RyanCavanaugh RyanCavanaugh added the Question An issue which isn't directly actionable in code label Feb 21, 2020
@typescript-bot
Copy link
Collaborator

This issue has been marked as 'Question' and has seen no recent activity. It has been automatically closed for house-keeping purposes. If you're still waiting on a response, questions are usually better suited to stackoverflow.

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