An attempt to compile a list of examples of unsound behavior of Flow.
Flow doesn't check that all class properties are initialized in constructor:
class Foo {
bar: Bar;
constructor() {
// forgot to initialize bar
}
}
const foo = new Foo();
foo.bar.boom();
Workaround: none
Array element access is inherently unsound:
const arr: Array<Bar> = [new Bar, new Bar];
arr[100].boom();
The same is applicable to strings and dictionaries.
Workarounds:
Avoid using element access, use array methods and for..of
instead;
Declare array element type as optional (this can lead to some unintended behavior).
There are multiple ways to get implicit any (i. e. getting any
without typing
any
explicitly):
- importing untyped module;
- using built-in value that uses any in some way;
- using
Object
orFunction
; - error in
try-catch
;
Workarounds:
- use custom core libdefs and
--no-flowlib
flag, update them as necessary; - use IDE with support for
flow coverage
to visually identify unexpectedany
; - use
flow coverage
command as a part of build process; - avoid
Object
orFunction
, they are basically variants of any; - avoid
try-catch
;
Flow allows to delete mandatory properties (facebook/flow#2207)
const foo = new Foo();
delete foo.bar;
foo.bar.boom();
Workarounds:
- avoid using
delete
, usedelete
only with dictionaries;
const a = {};
a.bar.boom();
a.bar = { boom() {} };
Workarounds:
- avoid using unsealed objects, if possible;
- avoid accessing properties on unsealed objects, pass them as arguments instead;