Как избежать повторения определений типов в объявлениях модулей?

Заявление об ограничении ответственности: я все еще немного новичок в Flow и статической типизации в целом, поэтому вполне возможно, что я упускаю из виду что-то простое / очевидное в этом вопросе.

Скажем, у меня есть библиотека под названием my-library. Библиотека предоставляет пользователям один модуль index.js, который импортирует пару других модулей (moduleA.js и moduleB.js) для внутреннего использования.

Я хочу использовать Flow с этой библиотекой как для собственной разработки, так и в index.js.flow файле с объявлением модуля для пользователей библиотеки, которые также используют Flow. Таким образом, файловая структура будет выглядеть примерно так:

- index.js
- index.js.flow (contains the module declaration for library users)
- moduleA.js
- moduleA.js.flow (just exported type definitions, no module declaration)
- moduleB.js
- moduleB.js.flow (just exported type definitions, no module declaration)

Проблема в том, что объявление модуля index.js.flow должно использовать типы как из moduleA.js.flow, так и из moduleB.js.flow. (Причина, по которой у меня есть moduleA.js.flow и moduleB.js.flow вместо того, чтобы просто определять типы непосредственно в файлах .js, заключается в том, что определения типов в файлах .js будут удалены Babel, и я хочу, чтобы они все еще существовали где-то для пользователей библиотеки).

Я знаю, что следующее не выполняет проверку типов с помощью внешнего JS, который импортирует my-module:

index.js.flow (это не работает)

import type { SomeType } from './moduleA'

declare module 'my-module' {
  declare function exports(): {
    someMethod: () => SomeType
  }
}

SomeType, похоже, не может использоваться в объявлении модуля при его импорте, но определение его локально работает:

index.js.flow (это работает)

export type SomeType = string

declare module 'my-module' {
  declare function exports(): {
    someMethod: () => SomeType
  }
}

Таким образом, одно из решений - просто определить и экспортировать все типы из index.js.flow и просто импортировать их moduleA.js и moduleB.js (без включения файлов .js.flow для moduleA и moduleB), но кажется странным иметь все определения типов в корневом потоке file вместо .js.flow файлов, соответствующих модулям, из которых происходят эти типы.

В качестве альтернативы я знаю, что могу определить типы в соответствующих модулях для разработки и просто снова определить их в объявлении модуля index.js.flow, но я бы предпочел не повторять определения типов в двух разных местах, если это возможно.

Я был бы очень признателен за любую помощь в выяснении того, как это лучше всего организовать. (И опять же, я знаю, что есть довольно большая вероятность, что я делаю что-то глупое или упускаю из виду что-то очевидное.)


person Shane Cavaliere    schedule 15.08.2016    source источник
comment
Вы пытались заменить import type ... вместо import ...? Итак, ваша первая попытка будет начинаться с import type { SomeType } from './moduleA'   -  person Michiel Dral    schedule 16.08.2016
comment
Да, я имел в виду именно это - извините, это была опечатка. Я только что починил.   -  person Shane Cavaliere    schedule 16.08.2016


Ответы (1)


Назначение файлов .js.flow - действовать в точности как соответствующие файлы .js в вашей реализации, за исключением того, что они не переводятся Babel. В частности, они импортируют и экспортируют вещи так же, как соответствующие .js файлы. Кроме того, как .js файл автоматически связывается с модулем в зависимости от того, где он находится в файловой системе, так и файл .js.flow.

Следуя примеру в вопросе, предположим, что module.exports index.js - это функция, которая возвращает объект, содержащий свойство someMethod типа () => SomeType, где тип SomeType экспортируется moduleA.js. Тогда в index.js.flow может быть следующее:

// @flow

import type { SomeType } from './moduleA'

declare module.exports: () => {
  someMethod: () => SomeType;
};

И следующее в moduleA.js.flow:

// @flow

export type SomeType = string;

Предполагая, что мы поместили index.js.flow и moduleA.js.flow в src/node_modules/my-module/, мы можем проверить правильность нашей настройки, указав следующее в test.js в src/:

// @flow

var foo = require('my-module');

(foo().someMethod(): number); // error (string incompatible with number)
person Avik Chaudhuri    schedule 17.08.2016
comment
Отлично, спасибо! Похоже, проблема была в declare module 'my-module' части. Единственное изменение, которое мне пришлось сделать, чтобы заставить его работать, - это просто использовать declare module.exports: ..., как вы предложили. Вы знаете, почему это так? - person Shane Cavaliere; 17.08.2016
comment
Подумайте об этом так: .js.flow - это просто замена .js для проверки типов. Что declare module будет означать внутри обычного .js файла? Этот файл уже определяет модуль. В этом примере index.js уже определяет модуль my-module, поскольку находится в node_modules/my-module. Это именно то, что происходит и с .js.flow. Использование declare module в обычном .js или .js.flow файле должно быть ошибкой (в настоящее время это не так, но это ошибка). Его использование должно быть ограничено глобальными объявлениями, указанными в вашем .flowconfig. - person Avik Chaudhuri; 17.08.2016