Are { [string]: string } and { [string]: (string | number} } incompatible is right?

54 Views Asked by At

string and string | number are compatible, but { [string]: string } and { [string]: (string | number} } are incompatible.

Am i doing something wrong?

https://flow.org/try/#0PQKgBAAgZgNg9gdzCYAoVAXAngBwKZgAqAjGALxgDOGATgJYB2A5gNya4GEBM5VtjTMAB8wDAK4BbAEZ4abbPiIBmXgG8wAbWr1mAXQBcfHYIC+8jkQAsazdoEGiPE+ihiGAYwx04DMBICGjAAUAJSqqGBgAG7+NNHEhiS8AORQcHDJbJExcVFciTwUUcRsEdGx0UqJKhTqUrGGyfU0yWBmZTnRlonWRUpszkA

/* @flow */

type T1 = string;
type T2 = string | number;
type T3 = { [string]: string };
type T4 = { [string]: T2 }

function main(){
  var v1: T1 = 'foo';
  var v2: T2 = v1;

  var v3: T3 = { bar: 'bar' };
  var v4: T4 = v3;
}

13:   var v4: T4 = v3;
                   ^ Cannot assign `v3` to `v4` because string [1] is incompatible with number [2] in the indexer property. [incompatible-type]
References:
5: type T3 = { [string]: string };
                         ^ [1]
6: type T4 = { [string]: T2 }
                         ^ [2]
1

There are 1 best solutions below

0
Ricola On

Reason

This is normal and expected

If this was allowed, then you would be allowed to do

 v4.foo = 1;
 var expectAString : string = v3.foo;

And you would get a number even though due to v3's type you should have only got a string.

Solution

Mark the objects as read-only:

type T3 = $ReadOnly<{ [string]: string }>;
type T4 = $ReadOnly<{ [string]: T2 }>;

Flow try link

Since they are read-only this prevents you to actually do v4.foo = 1;.

Note

This is the same for array, see this answer.

Docs