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

Cannot pass Array<T> to a function expecting Array<?T>

silverlyra opened this issue · comments

I just discovered some behavior regarding arrays of maybe types that I found surprising:

const lengths = (strings: Array<?string>): Array<number> =>
    strings.map((s) => s ? s.length : 0)

let strings: Array<string> = ['hello', 'world']
lengths(strings) // Flow error

An Array<T> cannot be passed as an argument for a parameter of type Array<?T>, even though all values in an Array<T> are valid in an Array<?T>. 👉 try flow

Casting via any works, but is nasty. Is this expected behavior? Is there a workaround other than casting to any?

I'm sorry if this is already a reported issue; I couldn't find it.

I believe the issue is that if the function takes strings: Array<?string> then you're allowed to, e.g., do strings.push(null), which is invalid on an Array<string>.

If the necessary subtyping were allowed, then lengths could corrupt the type of externalStrings, e.g.

const lengths = (strings: Array<?string>): Array<number> => {
    strings[0] = null; // I've just corrupted `externalStrings`
    strings.map((s) => s ? s.length : 0);
}

let externalStrings: Array<string> = ['hello', 'world']
lengths(externalStrings) // Flow error

You can use $ReadOnlyArray now apparently, though not sure if it's documented:
https://github.com/facebook/flow/blob/v0.48.0/lib/core.js#L185
#3425 (comment)

I believe the issue is that if the function takes strings: Array<?string> then you're allowed to, e.g., do strings.push(null), which is invalid on an Array<string>.

ahhhhhhhh. right. mutability. never caused anyone any problems. 🙄

thank you – that makes perfect sense. $ReadOnlyArray is perfect for my use case.