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
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>
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)
Most helpful comment
Short answer
If you use
$ReadOnlyArrayinstead ofArraythings will work fine.# Long Answer
Array types are invariant. This is because they are mutable. Therefore,
A is a subtype of B, DOES NOT implyArray<A> is 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
Bto it. But every B is NOT of type A. And that would be a type error.However, if you use
$ReadOnlyArrayinstead of Array, you won't be allowed to mutateyat 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)