Flow: Array<Array<string | number>> does not allow Array<Array<number>> as an input

Created on 11 Mar 2017  路  5Comments  路  Source: facebook/flow

type DatabaseQueryParametersType =
  Array<
    Array<string | number>
    >;

type DatabaseConnectionType = {
  query: (query: string, paramters: DatabaseQueryParametersType) => void
};

const getGenresByMovieIds = (connection: DatabaseConnectionType, movieIds: Array<number>): void => {
  connection
    .query('', [
        movieIds
    ]);
};

gives error:

3:     Array<string | number>
             ^ string. This type is incompatible with
10: const getGenresByMovieIds = (connection: DatabaseConnectionType, movieIds: Array<number>): void => {
                                                                                     ^ number

https://flowtype.org/try/#0C4TwDgpgBAIghsOAjOBnCBFArhATiABTlzgFsJg9UAVcaAXgCgooBBXEkAHmZbY7jdUwXAEsAdgHMoAHyjispJHgB8vFioDcjRqEiwEyNBADCAe3HiIAY2CiLtffSgBvXgEcc+AFxQAFJ54IL7CYlIANFBgxGSUuKi+8Igo6NhBRCTkcTR0AJRQ9CpQAG5mogAmjAC+2iyM1hbCUJIUAOIQ4rgQqABCIACyZsWiEACS5agF-g2WNnYWiYYpphZWtvbijhCRpEMj4wn8nFwKSqq5vqUVBUVuLDNr8+LqUAB0gfh+AORfkQDaLwAkLthmMJi8ALq5bQ1RhAA

Most helpful comment

Short answer

If you use $ReadOnlyArray instead of Array things will work fine.

# Long Answer

Array types are invariant. This is because they are mutable. Therefore, A is a subtype of B, DOES NOT imply Array<A> is a sub-type of Array<B>.

var a: A;
(a: B); // no-error

var x: Array<A>;
var y: Array<B> = x; // ERROR: Array<A> is not a sub-type of Array<B>;

Why?

Because if you mutated y and added elements to it the type system would only require you to add something of type B to it. But every B is NOT of type A. And that would be a type error.

However, if you use $ReadOnlyArray instead of Array, you won't be allowed to mutate y at all, so $ReadOnlyArray<A> is a sub-type of $ReadOnlyArray<B>.

https://flowtype.org/try/#0CYUwxgNghgTiAEkoGdnwELwN4F8BQoSci0q8AgvCAB4AuIAdsGprngeNMQG6zxQAuCgG48ACkEYAlKI5EEvGPGpDyMGFACeAHnIA+UYviahAEgBKIKMADyDCJrUad6PfAC8y2XiA


Further Reading:

https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

All 5 comments

Interestingly, a literal Array<number> does work:

https://flowtype.org/try/#0C4TwDgpgBAIghsOAjOBnCBFArhATiABTlzgFsJg9UAVcaAXgCgooBBXEkAHmZbY7jdUwXAEsAdgHMoAHyjispJHgB8vFioDcjRqEiwEyNBADCAe3HiIAY2CiLtffSgBvXgEcc+AFxQAFJ54IL7CYlIANFBgxGSUuKi+8Igo6NhBRCTkcTR0AJRQ9CpQAG5mogAmjAC+2iyM1hbCUJIUAOIQ4rgQqABCIACyZsWiEACS5agF-g2WNnYWiYYpphZWtvbijhCRpEMj4wn8nFwKSqq5vqUVBUVuLDNr8+LqUAB0gfh+AORfkQDaLwAkH8AIyRABMkQAzABdF4w3LaGqMIA

If you end up mutating the array in getGenresMovieIds, this could break the type contract. You could for instance push a string in it.

To make it work, instead of using Array<string | number>, you can use $ReadOnlyArray<string | number>

I see, but then why does Array<number> work?

https://flowtype.org/try/#0C4TwDgpgBAIghsOAjOBnCBFArhATiABTlzgFsJg9UAVcaAXgCgooBBXEkAHmZbY7jcAdllJI8APl4sJAbkaNQkWAmRoIAYQD2QoRADGwAJY7ay+lADevAI458ALigAKO3hBPUwXEaEBzABooMGIySlxUJ3hEFHRsdyIScnCaOgBKKHoJKAA3LSMAE0YAX3kWRn0dLyg-CgBxCCFcCFQAIRAAWS0cowgASQLUTJdK3QNjHSjVWM0dPUMTITMIINJu3oHI-k4uETFJNKc8wszs6xZR+YmhaSgAOjd8ZwByZ6CAbVuASDWe-sHbgBdNLyUqMIA

The thing is Array<number> is not a subtype of Array<number | string>.

const arr: Array<number> = [1];
func(arr); // this function adds a string to arr, because it accepts Array<string | number>
// now arr is not anymore an Array<number>

Short answer

If you use $ReadOnlyArray instead of Array things will work fine.

# Long Answer

Array types are invariant. This is because they are mutable. Therefore, A is a subtype of B, DOES NOT imply Array<A> is a sub-type of Array<B>.

var a: A;
(a: B); // no-error

var x: Array<A>;
var y: Array<B> = x; // ERROR: Array<A> is not a sub-type of Array<B>;

Why?

Because if you mutated y and added elements to it the type system would only require you to add something of type B to it. But every B is NOT of type A. And that would be a type error.

However, if you use $ReadOnlyArray instead of Array, you won't be allowed to mutate y at all, so $ReadOnlyArray<A> is a sub-type of $ReadOnlyArray<B>.

https://flowtype.org/try/#0CYUwxgNghgTiAEkoGdnwELwN4F8BQoSci0q8AgvCAB4AuIAdsGprngeNMQG6zxQAuCgG48ACkEYAlKI5EEvGPGpDyMGFACeAHnIA+UYviahAEgBKIKMADyDCJrUad6PfAC8y2XiA


Further Reading:

https://en.wikipedia.org/wiki/Covariance_and_contravariance_(computer_science)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

funtaps picture funtaps  路  3Comments

iamchenxin picture iamchenxin  路  3Comments

mjj2000 picture mjj2000  路  3Comments

bennoleslie picture bennoleslie  路  3Comments

jamiebuilds picture jamiebuilds  路  3Comments