I'm learning Flow and therefore I'm working on a little hobby project with JavaScript and Flow. I have a class Foo
and a different class Bar
that I want to take in an array of Foo
objects as an option in the constructor. However, I also want to be able to send some other data for each such object, and so I want to have an array where each element is either a plain Foo
object, or a Foo
object wrapped in an array or object.
However, when I tried to write the code for this, I got some weird errors that I don't understand the reason for. As far as I can tell, it thinks that there's a type conflict because Foo
isn't compatible with all of the types of the union, but as far as I understand it should only have to be compatible with at least one of them...
Here's the minimal code I needed to reproduce the exact errors I got (link to Try Flow example):
// @flow
class Foo { }
interface BarOptions {
foos: ( Foo | [ Foo ] | { foo: Foo } )[]; // line 6
}
class Bar {
constructor(options?: BarOptions) { }
}
const foo: Foo = new Foo();
const bar = new Bar({
foos: [ foo ], // line 16
});
I get the following errors:
Line 6:
tuple type: This type is incompatible with Foo
object type: This type is incompatible with Foo
Line 16:
tuple type: This type is incompatible with Foo
object type: This type is incompatible with Foo
Is there a intuitive (or unintuitive) reason for these errors?
I think
BarOptions
should actually be a type alias instead of an interface. An interface declares a type that classes can implement. Interfaces are not data types and they should not have fields (containing data).Here everything works if we just change
interface BarOptions
totype BarOptions =
.Alternatively you can change
foo
to become a getter function: