Безопасная компиляция при использовании полифилов

Допустим, у меня есть проект с двумя машинописными файлами:

  • a.ts
  • Б.Ц.

Мой tsconfig.json:

{
    "target": "ES5",            // old browser support is required
    "lib": ["dom", "es5"],      // 
    "types": []                 // 
}

Я оставил настройки типов пустыми, так как не хочу получать наборы из каких-либо сторонних пакетов (например, @types/ typings узлов, установленных как зависимость пакета webpack-dev-server; подробности ЗДЕСЬ)

Теперь я решил использовать новую функцию JS и добавил следующую строку в файл a.ts:

let clone = Object.assign({}, {a:1});

К счастью, компилятор достаточно умен, чтобы предупредить меня следующим предупреждением:

a.ts:1:20 - error TS2339: Property 'assign' does not exist on type 'ObjectConstructor'.

Поэтому мне нужно добавить полифилл (например, пакет CORE-JS) и добавить оператор импорта в a.ts:

import 'core-js/modules/es.object.assign'
let clone = Object.assign({}, {a:1});

Но компилятор машинописного текста все еще недоволен, поскольку в нем нет набранных типов для моего недавно заполненного метода присваивания. Я попытался установить пакет @types/ core-js и добавить его имя в мой файл tsconfig.json, но он не сработал, поэтому я создал свой собственный файл определения типа object.d.ts:

interface ObjectConstructor {
    assign(target: any, ...sources: any[]): any;
}

Все начало работать. Ура!

Затем я добавил еще одну новую функцию, но на этот раз в файле b.ts.

import 'core-js/modules/es.array.from'
console.log(Array.from('foo'));

И я также добавил определение типа для нового метода (файл array.d.ts):

interface ArrayConstructor {
    from<T>(arrayLike: ArrayLike<T>): T[];
}

И теперь, поскольку оба моих файла для печати доступны глобально, я могу использовать Array.from в a.ts и Object.assign в b.ts, и это проблема. Если я не добавлю

import 'core-js/modules/es.object.assign'

для b.ts код не будет работать в старых браузерах, и компилятор не скажет мне об этом.

Итак, вот мои вопросы:

  1. Можно ли использовать определения типов из @types/ core-js и выставлять типы по одному (поскольку я добавляю для них полифилы)?
  2. Можно ли сделать мои собственные определения типов видимыми для определенных файлов (не глобально видимыми), поэтому я буду иметь контроль над тем, что заполняется в каждом файле?

PS: я не буду связывать мои два файла, так как они должны быть доставлены отдельно. Извлечение импорта polyfill в отдельные модули и последующее добавление импорта в этот модуль в каждом файле не является для меня желательным вариантом, так как это потенциально создаст ссылки на polyfill, которые не используются в моих файлах, и я хочу, чтобы файлы результатов были такими маленькими, как возможно.

1 ответ

Решение

Эта конкретная форма заявления на импорт, которую вы используете

import 'core-js/modules/es.object.assign'

называется "импорт только для побочных эффектов", по причине. Этот оператор не оказывает никакого влияния на область видимости модуля, где появляется импорт, эффект, если он присутствует, является глобальным и не очевиден, если только вы не исследуете, что на самом деле делает код в импортированном модуле.

Эти конкретные полифилы добавляют статические методы к глобальным Object а также Array Конструкторы.

Таким образом, ваши определения типов для этих полифилов, кажется, работают правильно, по крайней мере, если a.js а также b.js будут выполняться в одном контексте выполнения и совместно использовать одни и те же глобальные объекты.

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

Можно ли сделать мои собственные определения типов видимыми для определенных файлов (не глобально видимыми), поэтому я буду иметь контроль над тем, что заполняется в каждом файле?

Это необходимо только в том случае, если каждый файл будет выполняться в своем собственном контексте выполнения, например, один файл находится на веб-странице, а другой файл - в коде работника сервиса. Тогда код в каждом файле фактически ссылается на разные глобальные объекты, но TypeScript не имеет адекватного способа представить, что, когда файлы компилируются вместе - во время компиляции (для объявлений типов) существует только одна глобальная область. В этом случае вы должны скомпилировать каждый файл в отдельный проект с отдельным tsconfig.json файлы и включают в себя наборы для Array.from а также Object.assign только там, где они нужны.

Другие вопросы по тегам