File Module Details
Шаблон зовнішнього модуля TypeScript містить велику потужність і зручність використання. Тут ми обговорюємо його потужність і деякі моделі, необхідні для відображення використання в реальному світі.
Clarification: commonjs, amd, es modules, others
Спочатку нам потрібно прояснити (жахливу) невідповідність систем модулів. Я просто дам вам свою поточну рекомендацію та видалю шум, тобто не покажу всі інші способи роботи.
З того самого TypeScript ви можете генерувати різний JavaScript залежно від параметра module. Ось речі, які ви можете ігнорувати (мені не цікаво пояснювати мертві технології):
AMD: не використовувати. Був лише браузер.
SystemJS: це був хороший експеримент. Замінено модулями ES.
Модулі ES: ще не готові.
Тепер це лише варіанти для генерування JavaScript. Замість цих параметрів використовуйте module:commonjs
Те, як ви пишете модулі TypeScript, також є дещо безладним. Ось як цього не робити сьогодні:
import foo = require('foo'). тобтоimport/require. Натомість використовуйте синтаксис модуля ES.
Круто, покінчивши з цим, давайте розглянемо синтаксис модуля ES.
Резюме: Використовуйте
module:commonjsі використовуйте синтаксис модуля ES для імпорту/експорту/авторських модулів.
ES Module syntax
Експортувати змінну (або тип) так само просто, як додати префікс ключового слова
export.
// file `foo.ts`
export let someVar = 123;
export type SomeType = {
foo: string;
};Експортування змінної або типу в спеціальному операторі
export.
// file `foo.ts`
let someVar = 123;
type SomeType = {
foo: string;
};
export {
someVar,
SomeType
};Експортування змінної або типу в спеціальному операторі
exportз перейменуванням.
// file `foo.ts`
let someVar = 123;
export { someVar as aDifferentName };Імпорт змінну або тип за допомогою
import.
// file `bar.ts`
import { someVar, SomeType } from './foo';Імпортуйте змінну або тип за допомогою
importз перейменуванням.
// file `bar.ts`
import { someVar as aDifferentName } from './foo';Імпортуйте все з модуля в назву за допомогою
import * as, наприклад.
// file `bar.ts`
import * as foo from './foo';
// you can use `foo.someVar` and `foo.SomeType` and anything else that foo might export.Імпортуйте файл тільки для його побічного ефекту за допомогою одного оператора імпорту:
import 'core-js'; // a common polyfill libraryПовторний експорт усіх елементів з іншого модуля
export * from './foo';Повторний експорт лише деяких елементів з іншого модуля
export { someVar } from './foo';Повторний експорт лише деяких елементів з іншого модуля * з перейменуванням *
export { someVar as aDifferentName } from './foo';Default exports/imports
Як ви дізнаєтесь пізніше, я не прихильник експорту за замовчуванням. Тим не менш, тут є синтаксис для експорту та використання стандартних експортів
Експортуйте за допомогою
export defaultперед змінною (не потрібно
let / const / var)перед функцією
перед уроком
// some var
export default someVar = 123;
// OR Some function
export default function someFunction() { }
// OR Some class
export default class SomeClass { }Імпортуйте за допомогою синтаксису
import someName from "someModule"(ви можете назвати імпорт як завгодно).
import someLocalNameForThisFile from "../foo";Module paths
Я просто припускаю
moduleResolution: "Node". Це параметр, який ви повинні мати у своїй конфігурації TypeScript. Цей параметр автоматично передбачаєтьсяmodule:commonjs.
Є два різних типи модулів. Розрізнення визначається розділом шляху оператора імпорту (наприклад, import foo from 'THIS IS THE PATH SECTION').
Модулі відносного шляху (де шлях починається з
., наприклад./someFileабо../../someFolder/someFileтощо)Інші модулі динамічного пошуку (наприклад,
'core-js'або'typestyle'або'react'або навіть'react/core'тощо)
Основна відмінність полягає в тому, як модуль вирішується у файловій системі.
Я буду використовувати концептуальний термін місце, який я поясню після згадки шаблону пошуку.
Relative path modules
Легко, просто дотримуйтеся відносного шляху :)
якщо файл bar.ts виконує імпорт * як foo з './foo';, тоді місце foo має існувати в тій же папці.
якщо файл
bar.tsвиконуєімпорт * як foo з '../foo';, тоді місцеfooмає існувати в папці вище.якщо файл
bar.tsвиконуєімпорт * як foo з '../someFolder/foo';, тоді на одну папку вище, має бути папкаsomeFolderз місцемfoo
Або будь-який інший відносний шлях, який ви можете придумати :)
Dynamic lookup
Якщо шлях імпорту не відносний, пошук керується роздільністю стилю вузла. Тут я наведу лише простий приклад:
У вас є
імпорт * як foo з 'foo', нижче наведено місця, які перевіряються по порядку./node_modules/foo../node_modules/foo../../node_modules/fooДо кореня файлової системи
У вас є
імпорт * як foo з 'something/foo', нижче наведено місця, які перевіряються по порядку./node_modules/something/foo../node_modules/something/foo../../node_modules/something/fooДо кореня файлової системи
What is place
Коли я кажу місця, які перевіряються, я маю на увазі, що в цьому місці перевіряються такі речі. Наприклад. для місця foo:
Якщо місцем є файл, напр.
foo.ts, ура!інакше, якщо місцем є папка і є файл
foo/index.ts, ура!інакше, якщо місцем є папка і існує
foo/package.jsonі файл, указаний у ключіtypesу package.json, тоді ура!інакше, якщо місцем є папка, і існує
package.jsonі файл, указаний у ключіmainу package.json, який існує, тоді ура!
Під файлом я насправді маю на увазі .ts / .d.ts і .js.
І це все. Тепер ви експерт із пошуку модулів (це не маленький подвиг!).
Overturning dynamic lookup just for types
Ви можете оголосити модуль глобально для свого проекту за допомогою declare module 'somePath', а потім імпорт буде чарівним чином вирішувати цей шлях
e.g.
// global.d.ts
declare module 'foo' {
// Some variable declarations
export var bar: number; /*sample*/
}and then:
// anyOtherTsFileInYourProject.ts
import * as foo from 'foo';
// TypeScript assumes (without doing any lookup) that
// foo is {bar:number}
import/require for importing type only
import/require for importing type onlyНаступна заява:
import foo = require('foo');насправді робить дві речі:
Імпортує інформацію про тип модуля foo.
Визначає залежність часу виконання від модуля foo.
Ви можете вибирати так, щоб завантажувалася лише інформація про тип і не виникала залежність під час виконання. Перш ніж продовжити, можливо, ви захочете підсумувати розділ просторів для оголошень у книзі.
Якщо ви не використовуєте імпортоване ім’я в просторі оголошення змінних, імпорт буде повністю видалено зі згенерованого JavaScript. Це найкраще пояснити на прикладах. Як тільки ви це зрозумієте, ми представимо вам випадки використання.
Example 1
import foo = require('foo');створить JavaScript:
Це вірно. Порожній файл як foo не використовується.
Example 2
import foo = require('foo');
var bar: foo;створить JavaScript:
var bar;Це тому, що foo (або будь-яка з його властивостей, наприклад foo.bas) ніколи не використовується як змінна.
Example 3
import foo = require('foo');
var bar = foo;створить JavaScript (припускаючи, що commonjs):
var foo = require('foo');
var bar = foo;Це тому, що foo використовується як змінна.
Use case: Lazy loading
Висновок типу потрібно зробити заздалегідь. Це означає, що якщо ви хочете використовувати певний тип із файлу foo у файлі bar, вам доведеться зробити:
import foo = require('foo');
var bar: foo.SomeType;Однак ви можете завантажувати файл foo лише під час виконання за певних умов. У таких випадках вам слід використовувати імпортовану назву лише в анотаціях типу, а не як змінну. Це видаляє будь-який попередній код залежності часу виконання, який впроваджується TypeScript. Потім вручну імпортуйте фактичний модуль, використовуючи код, який відповідає вашому завантажувачу модулів.
Як приклад, розглянемо наступний код на основі commonjs, де ми завантажуємо модуль `'foo`` лише під час певного виклику функції:
import foo = require('foo');
export function loadFoo() {
// This is lazy loading `foo` and using the original module *only* as a type annotation
var _foo: typeof foo = require('foo');
// Now use `_foo` as a variable instead of `foo`.
}Схожий приклад на amd (using requirejs) буде:
import foo = require('foo');
export function loadFoo() {
// This is lazy loading `foo` and using the original module *only* as a type annotation
require(['foo'], (_foo: typeof foo) => {
// Now use `_foo` as a variable instead of `foo`.
});
}Цей шаблон зазвичай використовується:
у веб-додатках, де ви завантажуєте певний JavaScript за певними маршрутами,
у вузлових програмах, де ви завантажуєте лише певні модулі, якщо це необхідно для прискорення завантаження програми.
Use case: Breaking Circular dependencies
Подібно до випадку використання відкладеного завантаження, деякі завантажувачі модулів (commonjs/node і amd/requirejs) погано працюють із циклічними залежностями. У таких випадках корисно мати ліниве завантаження коду в одному напрямку та завантаження модулів наперед в іншому напрямку.
Use case: Ensure Import
Іноді ви хочете завантажити файл лише для побічного ефекту (наприклад, модуль може зареєструватися в якійсь бібліотеці, наприклад CodeMirror addons тощо). Однак, якщо ви просто виконуєте команду import/require, транспільований JavaScript не міститиме залежності від модуля, і ваш завантажувач модуля (наприклад, веб-пакет) може повністю ігнорувати імпорт. У таких випадках ви можете використовувати змінну ensureImport, щоб переконатися, що скомпільований JavaScript приймає залежність від модуля, наприклад:
import foo = require('./foo');
import bar = require('./bar');
import bas = require('./bas');
const ensureImport: any =
foo
&& bar
&& bas;Last updated