facebook / flow

Adds static typing to JavaScript to improve developer productivity and code quality.

Home Page:https://flow.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Array<A|B> should be compatible with Array<A>

aldendaniels opened this issue · comments

This:

declare function func(things: Array<string | number>): void;
declare var value: string[];
func(value);

Gives:

1: declare function func(things: Array<string | number>): void;
                                                ^ number. This type is incompatible with
2: declare var value: string[];
                      ^ string

Perhaps related: #2507

Arrays are invariant: T being a subtype of U does not mean Array<T> is a subtype of Array<U>. Otherwise you could push a number onto things inside of func and there would be a number in value, which has type Array<string>.

Can't because func(value) could add a number to value.

function func(things: Array<string | number>): void {
  things.push(1);
}
var value: string[] = ['f'];
func(value);
console.log(typeof value[1]); // a number!

@jesseschalken @omerzach Wow, thanks for the quick follow up! Is there a way to make flow allow this if the function doesn't mutate the array - e.g. using a readonly array?

You can use func<T:string|number>(things: Array<T>): void or, of any Iterable will do, func(things: Iterable<string|number>): void (Iterable<T> is covariant in T).

See also #2333

@jesseschalken Sure enough! func(things: $ReadOnlyArray<T>) also appears to work

Closing in favor of #2333