10

This doesn't compile on the "Try Flow":

/* @flow */

type A = { a: number, b: string};
type B = { a: string, b: string };

const x: A = { a:1, b:'2' };
const y: B = { ...x, a: x.a.toString() }

Error is:

const y: B = { ...x, a: x.a.toString() }
                ^ Cannot assign object literal to `y` because number [1] is incompatible with string [2] in property `a`.

    References:

    3: type A = { a: number, b: string};
                     ^ [1]

    4: type B = { a: string, b: string };
                     ^ [2]

Note that this code works in TypeScript (when I remove field override it fails to compile as it is supposed to).

How to achieve same behavior in Flow without enumerating all fields of original object?

2 Answers 2

3

Some major improvements to spreads are coming out in Flow v0.111.0, scheduled for release next week. This snippet will now typecheck. You can see it in action now in flow.org/try by switching to the "master" version.

2

Short answer: you can't do this, and it's a "known" bug in Flow. It is "known" but I didn't see any indication that someone is actually working on it.

You can:

  • declare B.a to be a union of number | string.
  • declare a mapping function like this:

    const mapfn = ({ a, ...rest }: A): B => ({ ...rest, a: a.toString() });
    
    const x: A = { a: 1, b: '2' };
    const y: B = mapfn(x);
    

EDIT: it seems you can now do this with the newest version of Flow. See the above issue for details, they've fixed this bug. Upgrade your Flow!

Not the answer you're looking for? Browse other questions tagged or ask your own question.