Понимание TypeScript 4.7 и поддержки модулей ECMAScript

Автор Джон Рейли✏️

Выпуск TypeScript 4.7 включает серьезное обновление поддержки модулей ECMAScript для Node.js. В этой статье мы рассмотрим, что это значит.

  • Поддержка TypeScript
  • Создание модуля
  • Добавление TypeScript 4.7
  • Написание модулей TypeScript ECMAScript
  • ECMAScript и CommonJS бок о бок
  • Какие файлы создаются?

Краткая история модулей ECMAScript

Когда в 2015 году был выпущен ES6, вместе с ним появилась концепция модулей для JavaScript. Тогда они были известны как “модули ES6”. Сегодня они называются модулями ECMAScript (ESM).

В то время как написание кода с использованием семантики модулей ECMAScript быстро пришло для front end, для back end (который обычно представляет собой Node.js) это не так. На это есть несколько причин:

  1. В Node.js уже существовала устоявшаяся система модулей под названием CommonJS.
  2. Сам Node.js изначально не предлагал поддержку модулей ECMAScript; в значительной степени из-за проблем, связанных с поддержкой CommonJS, а также модулей ECMAScript.

Однако с выходом Node.js 14 поддержка модулей ECMAScript появилась. Если вас интересуют подробности поддержки этих модулей, то стоит прочитать эту статью о модулях ECMAScript.

Поддержка TypeScript

Команда TypeScript экспериментировала с тем, как предложить поддержку модулей ECMAScript с точки зрения Node.js, и с выходом TypeScript 4.7 поддержка появилась.

В этой заметке мы протестируем эту поддержку, попытавшись создать простой модуль на TypeScript с использованием новой поддержки модулей ECMAScript. По ходу дела мы обсудим, как выглядит авторство модулей ECMAScript для Node.js в TypeScript.

Поехали!

Создание модуля

Мы создадим модуль с именем greeter – давайте инициализируем его:

mkdir greeter
cd greeter
npm init --yes
Вход в полноэкранный режим Выйти из полноэкранного режима

Теперь у нас есть package.json, который выглядит примерно так:

{
  "name": "greeter",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo "Error: no test specified" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}
Вход в полноэкранный режим Выход из полноэкранного режима

Node.js поддерживает новую настройку в package.json под названием type. Он может быть установлен либо в “module”, либо в “commonjs”. Цитируем документацию:

Файлы, заканчивающиеся на .js, загружаются как модули ES, если ближайший родительский файл package.json содержит поле верхнего уровня "type" со значением "module".

Исходя из этого, мы добавим "type": "модуль" в наш package.json.

Теперь мы совместимы с поддержкой модулей ECMAScript, давайте начнем добавлять TypeScript.

Добавление TypeScript 4.7

Для того чтобы мы могли использовать поддержку модулей TypeScript ECMAScript, мы установим TypeScript 4.7 (в настоящее время он находится в бета-версии):

npm install typescript@4.7.0-beta --save
Войдите в полноэкранный режим Выйти из полноэкранного режима

Установив его, инициализируем проект TypeScript:

npx tsc --init
Войти в полноэкранный режим Выйти из полноэкранного режима

Это создаст файл tsconfig.json, который содержит множество опций. Мы изменим опцию module на nodenext, чтобы включить поддержку модулей ECMAScript:

{
  "compilerOptions": {
    // ...
    "module": "nodenext" /* Specify what module code is generated. */,
    "outDir": "./lib" /* Specify an output folder for all emitted files. */,
    "declaration": true /* Generate .d.ts files from TypeScript and JavaScript files in your project. */

    // ...
  }
}
Войти в полноэкранный режим Выход из полноэкранного режима

Мы также установили опцию outDir, чтобы скомпилированный JavaScript попадал в этот каталог, и опцию declaration, чтобы генерировались файлы .d.ts. Мы также обновим раздел "scripts" нашего package.json, чтобы включить скрипты build и start:

  "scripts": {
    "build": "tsc",
    "start": "node lib/index.js"
  },
Вход в полноэкранный режим Выход из полноэкранного режима

Написание модулей TypeScript ECMAScript

Когда все готово, мы готовы написать несколько модулей TypeScript ECMAScript. Сначала мы напишем модуль greetings.ts:

export function helloWorld(): string {
  return 'hello world!';
}
Вход в полноэкранный режим Выход из полноэкранного режима

В этом нет ничего нового или удивительного; это просто модуль, экспортирующий единственную функцию с именем helloWorld. Все становится интереснее, когда мы пишем наш модуль index.ts:

import { helloWorld } from './greetings.js';

const greeting = helloWorld();

console.log(greeting);
Вход в полноэкранный режим Выход из полноэкранного режима

Код выше импортирует нашу функцию helloWorld и затем выполняет ее, записывая вывод в консоль.

Это не особенно примечательно, однако то, как мы импортируем, является примечательным.

Мы импортируем из './greetings.js'. В прошлом мы бы написали:

import { helloWorld } from './greetings';
Войти в полноэкранный режим Выйти из полноэкранного режима

Теперь мы пишем:

import { helloWorld } from './greetings.js';
Войти в полноэкранный режим Выйти из полноэкранного режима

Это может показаться немного странным и неестественным, потому что у нас нет greetings.js в нашей кодовой базе; только greetings.ts. Импорты, которые мы пишем, отражают код, который в конечном итоге будет выполнен; после того, как наш TypeScript будет скомпилирован в JavaScript. В модулях ES относительные пути импорта должны использовать расширения.

Самый простой способ продемонстрировать, что это законно, – выполнить следующий код:

npm run build && npm start
Войти в полноэкранный режим Выйти из полноэкранного режима

Что приводит к:

> greeter@1.0.0 build
> tsc

> greeter@1.0.0 start
> node lib/index.js

hello world!
Войти в полноэкранный режим Выйти из полноэкранного режима

Итак, это работает!

ECMAScript и CommonJS бок о бок

Частью поддержки модулей ECMAScript является возможность указать тип модуля файла на основе суффикса файла. Если вы используете .mjs, вы явно указываете, что файл является модулем ECMAScript. Если вы используете .cjs, вы явно говорите, что файл является модулем CommonJS. Если вы разрабатываете на TypeScript, вы используете mts и cts соответственно, и они будут транспонированы в mjs и cjs.

К счастью, Node.js позволяет модулям ES импортировать модули CommonJS, как если бы они были модулями ES с экспортом по умолчанию; это хорошая новость для взаимодействия. Давайте проверим это, написав модуль oldGreetings.cts:

export function helloOldWorld(): string {
  return 'hello old world!';
}
Вход в полноэкранный режим Выход из полноэкранного режима

Синтаксис точно такой же, как и раньше.

Мы настроим наш index.ts для использования этого:

import { helloWorld } from './greetings.js';
import { helloOldWorld } from './oldGreetings.cjs';

console.log(helloWorld());
console.log(helloOldWorld());
Войти в полноэкранный режим Выйти из полноэкранного режима

Обратите внимание, что мы импортируем из './oldGreetings.cjs'. Посмотрим, работает ли это:

npm run build && npm start
Вход в полноэкранный режим Выйти из полноэкранного режима

Что приводит к:

> greeter@1.0.0 build
> tsc

> greeter@1.0.0 start
> node lib/index.js

hello world!
hello old world!
Войти в полноэкранный режим Выйти из полноэкранного режима

Это действительно работает!

Какие файлы испускаются?

Прежде чем мы завершим работу, может быть интересно посмотреть, что делает TypeScript, когда мы запускаем нашу npm run build. Он переносит наш TypeScript в JavaScript в нашу директорию lib: Обратите внимание, что файл greetings.ts привел к файлам greetings.js и greetings.d.ts, тогда как oldGreetings.cts привел к файлам oldGreetings.cjs и oldGreetings.d.cts; это отражает различные типы представленных модулей.

Также интересно посмотреть на разницу в JavaScript. Если учесть, насколько похожи были исходные файлы. Если вы посмотрите на greetings.js:

export function helloWorld() {
  return 'hello world!';
}
Вход в полноэкранный режим Выход из полноэкранного режима

Это тот же код, что и greetings.ts, но со снятыми типами. Однако, если мы посмотрим на oldGreetings.cjs, то увидим следующее:

'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
exports.helloOldWorld = void 0;
function helloOldWorld() {
  return 'hello old world!';
}
exports.helloOldWorld = helloOldWorld;
Вход в полноэкранный режим Выход из полноэкранного режима

В середине находится тот же код, что и в oldGreetings.cts, но с убранными типами, а вокруг – код-шаблон, который TypeScript выдает для нас, чтобы облегчить взаимодействие.

Заключение

Мы увидели, как выглядит поддержка TypeScript для модулей ECMAScript и как настроить модуль для ее использования.

Если вы хотите более подробно ознакомиться с этой темой, то заметки о выпуске бета-версии TypeScript 4.7 – отличный ресурс.


Много пишете на TypeScript? Посмотрите запись нашей недавней встречи по TypeScript, чтобы узнать о написании более читабельного кода.

TypeScript привносит безопасность типов в JavaScript. Между безопасностью типов и читабельностью кода может возникнуть противоречие. Посмотрите запись, чтобы узнать о некоторых новых возможностях TypeScript 4.4.

Оцените статью
Procodings.ru
Добавить комментарий