Skip to content

Allow falsy | T spreads for falsy primitives#18451

Merged
sandersn merged 12 commits into
masterfrom
allow-booleans-in-spreads
Sep 15, 2017
Merged

Allow falsy | T spreads for falsy primitives#18451
sandersn merged 12 commits into
masterfrom
allow-booleans-in-spreads

Conversation

@sandersn

@sandersn sandersn commented Sep 13, 2017

Copy link
Copy Markdown
Member

Fixes #16326

Allow falsy union types like false | T or null | T in spread in order to allow conditionally spreading:

function f(shouldSpread: boolean, origin: A, spreadee: B) {
  return { ...origin, ...shouldSpread && spreadee };
}

It's worth noting that this works currently without strictNullChecks because the type of shouldSpread && spreadee is B. However, with strictNullChecks it becomes false | B.

This PR special-cases changes the isValidSpreadType check to allow falsy unions, which are unions that have (1) have one or more falsy types (2) whose non-falsy parts return true for isValidSpreadType. This is actually stricter than before; these spreads are no longer allowed:

var n = { ...null };
var u = { ...undefined };
var un = { ...null, ...undefined };

Earlier in the PR's history, I had to to create a bespoke Partial<T> which was pretty clunky, but this code is not actually needed to fix the example from #16326, which I believe is by far the most common pattern.

Special-case types produced by `bool && expr` with the type `false | T`.
This spreads `Partial<T>` instead of `false | T`.
@sandersn

Copy link
Copy Markdown
Member Author

Actually, this needs to work for all falsy types. This means that all primitives are allowed in spread types now. Not sure I like this change, but I'll leave it open for discussion.

@sandersn sandersn changed the title Allow booleans in spreads Allow all primitives in spreads Sep 13, 2017
Comment thread src/compiler/checker.ts Outdated
if (type.types.length === 2) {
// getFalsyFlagsOfTypes
// getTypeFacts
const i = Math.max(type.types.indexOf(falseType),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use removeDefinitelyFalsyTypes on the union, then check the identity of the output vs. input to know if you should get add undefined to the member when you are building the normal spread type.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. That also covers undefined and null, which I forgot.

Comment thread src/compiler/checker.ts Outdated
members.set(prop.escapedName, prop);
}
else {
const result = createSymbol(prop.flags | SymbolFlags.Optional, prop.escapedName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can we merge this with the main spreadtype creation logic?

Only create properties once, only if needed, and don't create an
intermediate anonymous type. The code is also inlined with the rest of
`getSpreadType`.
@sandersn

Copy link
Copy Markdown
Member Author

I added the actual code from #16326 and confirmed that I do, in fact, need the code that creates the equivalent of Partial<T> when spreading the type false | T (or any falsy type, including null | undefined, etc).

So I kept the code but made it more efficient and integrated with the existing getSpreadType code.

@sandersn sandersn changed the title Allow all primitives in spreads Allow falsy | T spreads for falsy primitives Sep 15, 2017
Intended for a different PR
Turns out partialising falsy unions wasn't needed -- I was just
returning the wrong thing when spreading primitives.
@sandersn

Copy link
Copy Markdown
Member Author

OK, the ad-hoc Partial<T> equivalent code is gone now.

@sandersn sandersn merged commit 088da79 into master Sep 15, 2017
@sandersn sandersn deleted the allow-booleans-in-spreads branch September 15, 2017 23:24
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Suggestion] Support conditionally setting keys with the spread operator

3 participants