My expectation is that following flow code should be legitimate
const a: [string] = ["Hello World"];
const b: [string | number] = a;
But Flow complains about it. I checked exactly the same code with TypeScript, and typescript considers code as correct.
Flow version: 1.138
I expect following code not to trigger any Flow issues. Link to Flow example code
In case of TypeScript this kind of cast works perfectly. Link to TypeScript example code
Looks like, Flow can not recognize that cast is actually from specific to more generic type, which should be allowed.
You need to declare b as a read only array which makes this sound. This is mainly due to sub-types which you can read about in the docs https://flow.org/en/docs/types/arrays/#toc-readonlyarray
const anExampleVariable: Array<string> = ["Hello World"];
const b: $ReadOnlyArray<string | number> = anExampleVariable;
Sadly, my use case is not a simple array. I checked TypeScript and Flow for much more complicated case with custom class now, which better reflects the use case I came here for.
https://www.typescriptlang.org/play?#code/MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48TwIyOhYeIQoRMZoiADmFG7IAO5wSKgYOASocgBE+UUN6gKB4tD4aVWZtTl5EgWF0AA+0IjZqCUh4VGx8YloyfF8QA
https://flow.org/try/#0MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48TwIyOhYeIQoRMZoiADmFG7IAO5wSKgYOASocgBE+UUN6gKB4tD4aVWZtTl5EgWF0AA+0IjZqCUh4VGx8YloyfF8QA
TypeScript can still deal with it, but Flow can't.
Do we say Flow it's just a limitation of Flow? Any way to still express the similar concept?
Can you rely on inference? Basically can you can remove the explicit typing for const anExampleVariable: GenericNumber<string> because unless your example is way more complicated it really shouldn't be necessary.
https://flow.org/try/#0MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48a7QyADucEioGDgEqHIARMZoiADmReoCgeLQ+DwIyOhYeIQoRKUV0AA+6W2oFG6hkdFxCWBJKfB8QA
Because what you've done here is that you've explicitly defined them as two separate types, so of course when you try to map it to another variable it throws an error.
GenericNumber isn't a type, it's a constructor for a type which can be GenericNumber<string> or GenericNumber<string | number>
@Brianzchen with your example, the type of the .zeroValue is neither string nor number, and practically cannot be used anywhere else without explicit guards.
https://flow.org/try/#0MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48a7QyADucEioGDgEqHIARMZoiADmReoCgeLQ+DwIyOhYeIQoRKUV0AA+6W2oFG6hkdFxCWBJKfACciNRsfGJaMnx9h4q3NBd5dXUc+EL48ur8OtKnqr9BSh7B6OLE1NrDpdbiAMovdsSZbt8QA
To maintain type safety, this might be a better approach https://flow.org/try/#0MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAagBUA+aAbwChpoSAvVAewDUwRt4AuaMgG56DYK0QQALimzBJrFAAoWKDlx78yAShoMA9HugBhcVJlyFIhpIAWaCADoVa7vGgBeaM86vhDAL60gWISktBgiACiAB5guAAOIPCc6GD4SfwIyOhYeIQoRGZoiADmVJ7IAO5wSKgYOASoigBERaXNWsIhUtD4mbU5DfmF0sUl0AA+0Ih5qOXhUbEJSSloaUmCQA
Basically in these situations we should think that we want to allow usage, but prevent mutations on the objects.
I agree with @reshadi that making zeroValue covariant / readonly is probably the way to go if you don't need to modify zeroValue.
As context for @guliashvili, this happens because of Flow's variance rules for generics that are stricter (invariant by default) than those in TypeScript.
Here's the runtime error that TypeScript fails to catch because they aren't so strict about this:
https://www.typescriptlang.org/play?#code/MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48TwIyOhYeIQoRMZoiADmFG7IAO5wSKgYOASocgBE+UUN6gKB4tD4aVWZtTl5EgWF0AA+0IjZqCUh4VGx8YloyfEC1Pj2HirObgAs1KGR0XEJYEkp8JtKnpy2MgCqMTGo+pDwcpq60ABK2IhiaFwzlQShQPAcN2cNgmTAqYAmUxQQA
Most helpful comment
I agree with @reshadi that making
zeroValuecovariant / readonly is probably the way to go if you don't need to modifyzeroValue.As context for @guliashvili, this happens because of Flow's variance rules for generics that are stricter (invariant by default) than those in TypeScript.
Here's the runtime error that TypeScript fails to catch because they aren't so strict about this:
https://www.typescriptlang.org/play?#code/MYGwhgzhAEDiCmA7eAnAlsAcgVwLYCNUAeAFQD5oBvAKGmgC9UB7ANTBG3gC5oSBuWnWBNEEAC4pswMUxQAKRilbtOPEgEoqdAPTboAYRHjJ02YLpiAFmggA6Rco7xoAXgbM2TgXQC+1P8KiYtBgiACiAB5guAAOIPBs6GD48TwIyOhYeIQoRMZoiADmFG7IAO5wSKgYOASocgBE+UUN6gKB4tD4aVWZtTl5EgWF0AA+0IjZqCUh4VGx8YloyfEC1Pj2HirObgAs1KGR0XEJYEkp8JtKnpy2MgCqMTGo+pDwcpq60ABK2IhiaFwzlQShQPAcN2cNgmTAqYAmUxQQA