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

Conditional types expand variants #24969

Closed
ppham27 opened this issue Jun 14, 2018 · 6 comments
Closed

Conditional types expand variants #24969

ppham27 opened this issue Jun 14, 2018 · 6 comments
Labels
Duplicate An existing issue was already created

Comments

@ppham27
Copy link

ppham27 commented Jun 14, 2018

TypeScript Version: 3.0.0-dev.20180609

Search Terms: conditional types, type inference, union, boolean

Code

type Wrap<V = undefined> = V extends {} ? {value: V} : {};
type BooleanWrap = Wrap<boolean>;
const coinFlip: BooleanWrap = { value: Math.random() > 0.5 };

Expected behavior: The assignment to coinFlip should work.

Actual behavior: I get the compiler error:

index.ts:3:7 - error TS2322: Type '{ value: boolean; }' is not assignable to type '{ value: false; } | { value: true; }'.
  Type '{ value: boolean; }' is not assignable to type '{ value: true; }'.
    Types of property 'value' are incompatible.
      Type 'boolean' is not assignable to type 'true'.

3 const coinFlip: BooleanWrap = { value: Math.random() > 0.5 };

The type of BooleanWrap should ideally be resolved to { value: boolean; }, but it is resolved to { value: false; } | { value: true; }. The same thing happens with any type union.

Playground Link: https://www.typescriptlang.org/play/index.html#src=type%20Wrap%3CV%20%3D%20undefined%3E%20%3D%20V%20extends%20%7B%7D%20%3F%20%7Bvalue%3A%20V%7D%20%3A%20%7B%7D%3B%0Atype%20BooleanWrap%20%3D%20Wrap%3Cboolean%3E%3B%0Aconst%20coinFlip%3A%20BooleanWrap%20%3D%20%7B%20value%3A%20Math.random()%20%3E%200.5%20%7D%3B

Related Issues: #24085

@weswigham
Copy link
Member

@ppham27

type Wrap<V = undefined> = [V] extends [{}] ? {value: V} : {};
type BooleanWrap = Wrap<boolean>;
const coinFlip: BooleanWrap = { value: Math.random() > 0.5 };

conditional types are distributive by default. To disable that, simply make the checked type not-a-bare-type-parameter, as above.

@RyanCavanaugh
Copy link
Member

@weswigham beat me by seconds. We should seed a StackOverflow question on this

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Jun 14, 2018
@ppham27
Copy link
Author

ppham27 commented Jun 14, 2018

This works for me. Thanks! Sorry for the bother. Is there some documentation that I'm missing about the bracket notation?

@ppham27 ppham27 closed this as completed Jun 14, 2018
@RyanCavanaugh
Copy link
Member

It's just the usual tuple syntax; any other wrapping of the type parameter would work, e.g. { foo: V }

@RyanCavanaugh
Copy link
Member

Oh and I should add, all types extend {}, you almost certainly wanted to use object there

@ppham27
Copy link
Author

ppham27 commented Jun 14, 2018

As an aside, I had to negate the predicate:

type Wrap<V = undefined> = [V] extends [undefined] ? {} : {value: V} ;

[V] extends [{}] evaluates to true when V = undefined.

I don't want object because [V] extends [object] does not evaluate to true when V = boolean.

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

3 participants