Flow: Potential spread operator bug

Created on 20 Jun 2018  路  5Comments  路  Source: facebook/flow

I'm trying to build a type that has a set of nested properties that will be extended by some method.

Try flow example

// this will what a "full built" meta should look like
type Meta = {|
  foo: string,
  bar: string
|}

// the full type "A" includes a full built meta
type A = {|
  type: string,
  meta: Meta
|}

// when creating a skinny vesion of A, we omit some attributes from meta
type NotPresentInSkinnyAMeta = {|
  foo: string
|}

// so SkinnyA.meta is a diff between the full built meta and the properties that shouldn't be present
type SkinnyA = {|
  type: string,
  meta: $Diff<Meta, NotPresentInSkinnyAMeta>
|}

// all good here, works as expected
const skinny: SkinnyA = {
  type: 'a',
  meta: {
    bar: 'b'
  }
}

// throws "Cannot assign object literal to `notSkinny` because property `foo` is missing in `Meta` [1] but exists in `Meta` [2] in property `meta`."
const notSkinny: A = {
  ...skinny,
  meta: {
    ...skinny.meta,
     foo: 'b'
  }
}
spread bug

Most helpful comment

Simpler repro (without $Diff, type, or skinny):

// @flow

type Meta = {|
  foo: string,
  bar: string,
|};

type A = {|
  meta: Meta
|};

const okay: A = {
  meta: {bar: 'b'},
  meta: {foo: 'a', bar: 'b'},
};

const notOkay: A = {
  ...{meta: {bar: 'b'}},  // errors, but shouldn't
  meta: {foo: 'a', bar: 'b'},
};

While this definitely seems like a bug, it鈥檚 not a particularly
surprising one. The spread operator sees that the target has an
attribute with key meta and value {bar: 'b'}, which is inconsistent
with $PropertyType<A, "meta"> (namely, Meta), so it complains. It is
failing to take into account that this property is overridden later in
the object anyway. At least, it seems to me that this is what鈥檚
happening.

All 5 comments

Simpler repro (without $Diff, type, or skinny):

// @flow

type Meta = {|
  foo: string,
  bar: string,
|};

type A = {|
  meta: Meta
|};

const okay: A = {
  meta: {bar: 'b'},
  meta: {foo: 'a', bar: 'b'},
};

const notOkay: A = {
  ...{meta: {bar: 'b'}},  // errors, but shouldn't
  meta: {foo: 'a', bar: 'b'},
};

While this definitely seems like a bug, it鈥檚 not a particularly
surprising one. The spread operator sees that the target has an
attribute with key meta and value {bar: 'b'}, which is inconsistent
with $PropertyType<A, "meta"> (namely, Meta), so it complains. It is
failing to take into account that this property is overridden later in
the object anyway. At least, it seems to me that this is what鈥檚
happening.

Related: #6498.

@Ricardo-Marques, that seems unrelated; the error persists if you
replace ...UnauthenticatedHeaders with Language: "en" | "es" to
inline the spread, and is more easily reproduced by

// @flow
const x: $Shape<{a: number} | {b: string}> = {a: 1};

Feel free to open a different thread.

This no longer errors in master

Was this page helpful?
0 / 5 - 0 ratings