TypeScript не может найти модуль, если он содержит требование

Я пытаюсь понять, как правильно работать с TypeScript и классическими модулями узла JS.

Я создал очень простой проект со следующей файловой архитектурой:

.
├── index.ts
├── lodash.d.ts
├── module.ts
└── node_modules
    └── lodash

lodash был установлен с npm. Поскольку он, похоже, не предоставляет информации о типизации, я написал базовый файл d.ts, который описывает только одну функцию, просто чтобы угодить tsc и избежать ошибки, связанной с незнанием lodash.

lodash.d.ts

declare module "lodash" {
  export function reverse(array: any[]): any[];
}

В моем файле module.ts я импортирую lodash с require и выставляю функцию в модуле, который я использую в файле index.ts.

module.ts

/// <reference path="./lodash.d.ts" />

import _ = require('lodash');

module FooModule {
  export function foo() {
    return _.reverse([1, 2, 3]);
  }
}

index.ts

/// <reference path="./module.ts" />

let a = FooModule.foo();
console.log(a);

Проблема в том, что tsc (и, следовательно, VS Code) сообщает мне, что не может найти имя FooModule.

$ tsc index.ts --module commonjs -outDir build
index.ts(3,9): error TS2304: Cannot find name 'FooModule'.

Однако, если я уберу import _ = require('lodash'); из module.ts, он будет работать корректно (за исключением того очевидного факта, что переменная _ теперь не определена).

Я что-то не так делаю с этим require?


person Blackus    schedule 25.02.2016    source источник


Ответы (1)


Вы смешиваете внутренние модули и внешние модули. Если вы используете оператор импорта или экспорта верхнего уровня в файле .ts, сам файл автоматически рассматривается как внешний модуль, а его содержимое является частью этого модуля (require является оператором импорта).

Если вы помещаете внутренний модуль во внешний модуль (ключевое слово module или namespace), вы фактически выполняете двойную упаковку содержимого вашего модуля. Это не хорошо.

Возьмем следующий пример:

module.ts

import _ = require('lodash');

module FooModule {
    export function foo() {
        return _.reverse([1, 2, 3]);
    }
}

Функция foo теперь фактически module.FooModule.foo, если вы экспортируете внутренний модуль FooModule из внешнего модуля module:

export module FooModule {
    // ...
}

Однако это плохо.

person John Weisz    schedule 25.02.2016
comment
Я понял, спасибо за понятное объяснение. Но если экспорт FooModule, как вы предложили в конце своего ответа, является плохой практикой, как это сделать? Или, если это более архитектурная проблема, как мне использовать модули узлов для частей кода, которые я хочу предоставить в своем проекте? - person Blackus; 25.02.2016
comment
@Blackus Просто удалите часть module FooModule и оставьте свои функции открытыми. Они будут частью модуля module (или как называется ваш файл, без расширения .ts). Кроме того, не забывайте, что вам понадобится система загрузки модулей во время выполнения (у Node.js есть встроенная). - person John Weisz; 25.02.2016
comment
Я, наконец, понял это, это просто работает как модули CommonJS (в данном случае). Что на самом деле меня очень сильно обмануло, так это то, что мой способ сборки (я использую веб-пакет с моим реальным проектом), который был неправильным, и все мои файлы не были правильно перестроены. Теперь все ясно. Спасибо еще раз :) - person Blackus; 25.02.2016