Reputation: 10341
/* @flow */
type optionsType = Array<{id: string | number, name: string}>;
type modelsType = Array<{id: number, name: string}>;
function getOptions(options: optionsType): string {
return options.reduce((a, e) => {
return a + `<option value="${e.id.toString()}">${e.name}</option>`;
}, '');
}
const options: modelsType = [
{id: 1, name: 'punto'},
{id: 2, name: 'duo'},
{id: 500, name: 'cinquecento'},
];
console.log(getOptions(options));
The above example complains Cannot call "getOptions" with "options" bound to "options" because number [1] is incompatible with string [2] in property "id" of array element.
but in my understanding the modelsType
is just more generic than the optionsType
. Why does flow complain and how can I get this to work as expected?
Upvotes: 1
Views: 1839
Reputation: 10341
The final solution to my use case:
/* @flow */
type optionsType = $ReadOnlyArray<{+id: string | number, name: string}>;
type modelsType = Array<{id: number, name: string}>;
function getOptions(options: optionsType): string {
return options.reduce((a, e) => {
return a + `<option value="${e.id.toString()}">${e.name}</option>`;
}, '');
}
const options: modelsType = [
{id: 1, name: 'punto'},
{id: 2, name: 'duo'},
{id: 500, name: 'cinquecento'},
];
console.log(getOptions(options));
Upvotes: 0
Reputation: 161457
If
let second: secondType = first;
were allowed as-is, it would mean that it's valid to do
second.id = "some-id";
but that would corrupt the type of firstType
since it's the same object, and the type is number
, but it's now been assigned a string.
To make this work, you need to say that secondType.id
is read-only, or "covariant". You can do this by changing
type secondType = {id: string | number, name: string};
to
type secondType = {+id: string | number, name: string};
Upvotes: 2