Объявить глобальную переменную с помощью внешнего модуля в TypeScript

Я создаю модуль npm в TypeScript https://www.npmjs.com/package/html2commonmark. Модуль можно использовать в nodejs (используя require) и из браузера (загружая node_modules/html2commonmark/dist/client/bundle.js в ваш браузер).

Недавно я добавил файлы * .d.ts, чтобы получать информацию о вводе при использовании "moduleResolution": "node". Это отлично работает, при установке моего модуля он готов для использования в машинописном тексте. Таким образом: следующий фрагмент машинописного кода компилируется без ошибок:

// After installing using npm install html2commonmark
// using "moduleResolution": "node"
import * as html2commonmark from 'html2commonmark';
let converter = new html2commonmark.JSDomConverter();

Красивый!

Теперь я хочу запустить свой модуль в браузере. Как упоминалось ранее, мне нужно добавить тег скрипта в node_modules/html2commonmark/dist/client/bundle.js на мою страницу index.html. После этого должна быть доступна глобальная переменная html2commonmark. Проблема в следующем: как я могу сообщить компиляции машинописного текста о наличии глобальной переменной? Следующий фрагмент кода TS не компилируется:

let converter = new html2commonmark.BrowserConverter(); 
// error TS2304: Cannot find name 'html2commonmark'.

Даже если я добавлю файл global.d.ts, мне не удастся импортировать внешний модуль и объявить глобальную переменную:

// Something like this does not work :(
import * as b from 'html2commonmark';
declare var html2commonmark: typeof b;

Я понимаю, почему это так. Используя ключевое слово import, мой ts-файл преобразуется во внешний модуль, и поэтому его необходимо импортировать. Тем не менее, я чувствую, что мой сценарий является обычным. А именно: модуль npm, содержащий как компонент npm, так и пакет для браузера, который предоставляет функциональность как глобальную переменную.

Есть ли способ объявить глобальную переменную, используя определение внутри моего внешнего модуля? Мне не хочется переписывать свой api как пространство имен (в стиле Определенного Типа), в то время как я только что написал весь исходный код в TS ...


person nicojs    schedule 09.02.2016    source источник


Ответы (1)


Правильные способы написать внешний модуль, работающий как в браузере, так и в Node.js:

  1. Используйте флаг --module umd, а затем используйте загрузчик AMD в браузере, чтобы загрузить модуль.
  2. Используйте флаг --module commonjs, а затем используйте пакет, например webpack или browserify

Другими словами, когда вы начинаете писать модульный код, слепое добавление тегов <script> в файл HTML больше не является правильным способом загрузки этого кода в браузер. Так же, как вы не должны касаться глобальной области в Node.js, вы также не должны касаться глобальной области в браузере. Вы можете взломать его с помощью if (typeof window !== 'undefined') (<any>window).global = yourObject;, но серьезно, никогда не делайте этого, это неправильно, и он сломается.

Что касается предоставления интерфейсов из внешних модулей в глобальную область видимости, это невозможно сделать, поскольку вам придется import внешний модуль, чтобы получить ссылку на его интерфейсы, после чего вы создали другой внешний модуль. Начиная с TypeScript 1.8, вы можете расширять глобальные типы из внутренних модулей, используя _ 6_.

person C Snover    schedule 09.02.2016
comment
Спасибо за ваш ответ! Для создания bundle.js я использую webpack. Конечно, я мог бы также заставить (машинописных) потребителей, пишущих для браузера, использовать webpack / browserify. Мне просто было интересно, есть ли способ лучше. Я чувствую, что это должно быть возможно. использование (<any>window).global = yourObject не требуется, потому что объект уже доступен в глобальной области (по крайней мере: при включении bundje.js на вашу страницу). Я просто ищу способ сделать это видимым для машинописного текста. - person nicojs; 09.02.2016
comment
В этом случае ответ будет намного проще: «нет» :) Вы можете предоставить глобальные интерфейсы именованным модулям в рукописных файлах d.ts с помощью declare module "foo" { export = SomeGlobal; }, но нет никакого другого пути. - person C Snover; 09.02.2016
comment
Это очень плохо. Если вы обновите свой ответ короткой версией, я отмечу его как правильный ответ - person nicojs; 10.02.2016
comment
Ты мой герой: if (typeof window !== 'undefined') (<any>window).global = yourObject; ;-) - person Huan; 06.05.2017