Flow: Object spread not handling booleans correctly

Created on 12 Mar 2018  路  10Comments  路  Source: facebook/flow

Using booleans to spread into objects does not work correctly:

Input:

const a = false;
const b = {
  ...(a && {}),
};

Output:

2: const b = {
             ^ boolean [1] is not an object.
References:
1: const a = false;
             ^ [1]

Expected Output:

No errors!

https://flow.org/try/#0MYewdgzgLgBAhjAvDAZnANhApgbgFCiSwBGSMA3njDAHR0AUCAZExQL4CUANHmzkA

Spreading false into an object does nothing, and if a was true, we would not spread a boolean, because we would move along the && to the object. So this should be permitted.

In Chrome:

Background: This pattern is used often when composing styles in CSS-in-JS libraries.

spread

Most helpful comment

I believe this is the best pattern to conditionally include a key during object declaration, and I would love to see this implemented in flow.
For the people that think this isn't legal js, tc39 explicitly confirmed that it is valid.

For anyone interested in a workaround while this isn't 'fixed', I'm currently using:

Instead of:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition && { key: 'value' }), 
}

I'm going with:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition ? { key: 'value' } : {}),
}

Even though it works with small objects, it gets funny when dealing with objects that span multiple lines, since the colon gets pushed down the code:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition ? {
    key: 'value',
    color: 'red',
    background: '1px solid black',
  } : {}),
}

I usually avoid using long ternaries.

All 10 comments

@TrySound, @danwang Why the downvotes? It took me a while, but this actually seems to be about something factual. Whatever you think about that expression, it does not result in a boolean as claimed by Flow. I would understand if Flow complains with __an__ error (Flow is opinionated after all and does not accept something just because it is possible in JS), but I don't understand the actual error.

PS: Here's the spec for object spread, in my current state I'm not capable of deciphering from this what is supposed to happen when there's a boolean instead of an object. Code generated by Babel works just fine though. I think item 1 under headline 2.3 applies (spec).

(OP) Of course, if there already is a boolean there are plenty of ways to achieve the desired outcome in other ways. Extreme brevity is not a goal when you use Flow.

@lll000111 this should probably have different message, but spreading boolean to object doesn't feel right. Though I can understand spreading null which has type object.

For reference, here's what the relevant pattern looks like:

const style = {
  display: "flex",
  justifyContent: "center",
  alignItems: "center",
  ...(disabled && {
    color: "#888",
    cursor: "auto",
  }),
};

There is some congruity with React.Node being a supertype of falsy values:

const a = false
return (
  <div>
    {a}
  </div>
);

I believe this is the best pattern to conditionally include a key during object declaration, and I would love to see this implemented in flow.
For the people that think this isn't legal js, tc39 explicitly confirmed that it is valid.

For anyone interested in a workaround while this isn't 'fixed', I'm currently using:

Instead of:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition && { key: 'value' }), 
}

I'm going with:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition ? { key: 'value' } : {}),
}

Even though it works with small objects, it gets funny when dealing with objects that span multiple lines, since the colon gets pushed down the code:

const condition = false
const myobj = {
  akey: 'a value',
  ...(condition ? {
    key: 'value',
    color: 'red',
    background: '1px solid black',
  } : {}),
}

I usually avoid using long ternaries.

I also have another workaround solution too. 馃ぃ

{...Array(condition)[0] && yourObject}

flow
demo on flow v0.80.0

Does the project no longer maintain?

@lehainam125 Do you see it's not maintained?
https://github.com/facebook/flow/commits/master

What's the status on this?

I don't think it is right to typecast false to {} like spread does.
Object.assign also disallows it

1: Object.assign({}, false)   ^ boolean [1] is not an object.
References:
1: Object.assign({}, false)
                     ^ [1]

TypeScript also doesn't support this

Was this page helpful?
0 / 5 - 0 ratings