Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use (or simulate) object spread with overriding fields in Flow?

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?

like image 399
menfon Avatar asked Oct 22 '18 07:10

menfon


2 Answers

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.

like image 88
Nat Mote Avatar answered Nov 18 '22 10:11

Nat Mote


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!

like image 2
Aleksandar Dimitrov Avatar answered Nov 18 '22 11:11

Aleksandar Dimitrov