Невозможно присвоить массив объектов массиву типов объединения в потоке

Я изучаю Flow, и поэтому я работаю над небольшим хобби-проектом с JavaScript и Flow. У меня есть класс Foo и другой класс Bar, который я хочу взять в массив объектов Foo в качестве опции в конструкторе. Тем не менее, я также хочу, чтобы иметь возможность отправлять некоторые другие данные для каждого такого объекта, и поэтому я хочу иметь массив, где каждый элемент является либо простым объектом Foo, либо объектом Foo, завернутым в массив или объект.

Однако, когда я попытался написать код для этого, у меня появились некоторые странные ошибки, которые я не понимаю. Насколько я могу судить, он считает, что существует конфликт типа, поскольку Foo несовместим со всеми типами объединения, но насколько я понимаю, он должен быть совместим хотя бы с одним из них...

Здесь минимальный код мне нужно было воспроизвести точные ошибки, которые я получил (ссылка на пример tryflow.org):

// @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
});

Я получаю следующие ошибки:

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

Есть ли интуитивная (или неинтуитивная) причина этих ошибок?

Ответ 1

Думаю, что BarOptions должен быть псевдонимом типа вместо интерфейса. Интерфейс объявляет тип, который классы могут реализовать. Интерфейсы не являются типами данных, и у них не должно быть полей (содержащих данные).

Здесь все работает, если мы просто изменим interface BarOptions на type BarOptions =.

В качестве альтернативы вы можете изменить foo, чтобы стать функцией getter:

interface BarOptions {
  foos(): ( Foo | [ Foo ] | { foo: Foo } )[];
}

Ответ 2

Считаете ли вы, что это может быть связано с этим открытым сообщением Github ? Если мы заменим interface на type, он проверяет:

// @flow

class Foo { }

type BarOptions ={
  foos: 
        Class<Foo> |
        Foo |
        Foo[] |
        { foo: Foo } 
}

class Bar {
  constructor(options?: BarOptions) { }
}

const foo: Foo = new Foo();

const bar = new Bar({
  foos: Foo,
//   foos: foo,
//   foos: [foo],
//   foos: { foo: foo },
});