Все статьи | Разработка

Как использовать аннотации типов в файлах JavaScript

Как использовать аннотации типов в файлах JavaScript главное изображение

TypeScript (TS) позволяет использовать аннотации типов в коде JavaScript. TS даже может проверять код при сборке, благодаря чему вы увидите ошибки до того, как они попадут в продакшен. Вы избавитесь от undefined is not a function навсегда.

TypeScript по умолчанию требует некоторых изменений при настройке окружения. Вам придётся переименовать файлы JavaScript в .ts, .tsx, а также использовать компиляторы tsc или Babel.

Синтаксис TypeScript

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

function repeat(text: string, count: number) {
  return Array(count + 1).join(text)
}

Синтаксис TypeScript позволяет использовать аннотации типов инлайн. Но сначала поговорим об альтернативах.

Документируем JavaScript

Синтаксис JSDoc

TypeScript можно документировать с помощью JSDoc. Это стандартный синтаксис для документирования JavaScript. JSDoc используется для создания документации, но TypeScript понимает аннотации типов, созданные с помощью этого инструмента.

/**
 * Repeats some text a given number of times.
 *
 * @param {string} text - The text to repeat
 * @param {number} count - Number of times
 */

function repeat(text, count) {
  return Array(count + 1).join(text)
}

Это значит, что у вас есть возможности использовать преимущество TypeScript, в частности, проверку типов, без необходимости конвертировать весь код.

Почему JSDoc

Применение JSDoc — полезная практика, даже если вы не используете TypeScript. Фактически это стандарт документирования JavaScript, и его поддерживают разные инструменты и редакторы.

Если вы уже применяете JSDoc, вам будет удобно использовать проверку типов в коде, аналогичную той, которая применяется в TypeScript. Для этого нужно уделить время настройке TypeScript.

Установка TypeScript

Как установить TypeScript

Чтобы установить в проект TypeScript, используйте такую команду:

npm install typescript
# или
yarn add typescript

Как включить проверку типов JSDoc

Теперь нужно настроить TypeScript, чтобы он проверял код в файлах JavaScript. По умолчанию он проверяет только файлы с расширением .ts. Настройки TypeScript надо указывать в файле tsconfig.json. Обратите внимание на опцию noEmit. Мы используем её, так как планируем применять TypeScript только для проверки типов.

{
  "compilerOptions": {
    "allowJs": true,
    "noEmit": true
  }
}

Настраиваем TypeScript

В начале файлов .js, в которых вам нужна проверка типов, добавьте комментарий:

// @ts-check

Запустите проверку типов. Это можно сделать с помощью команды:

./node_modules/.bin/tsc
# или
yarn run tsc

Рекомендуется использовать проверку типов также в инструментах непрерывной интеграции (CI).

Дальше поговорим о документировании кода с помощью JSDoc.

Базовые аннотации

Аннотации параметров функций

Для аннотации параметров функций используйте @param. Его нужно указать в комментариях JSDoc, которые начинаются с двух идущих подряд астериксов.

/**
 * @param {string} текст
 * @param {number} количество
 */

function repeat(text, count) {
  return Array(count + 1).join(text)
}

Документирование кода

JSDoc — инструмент для документирования. Кроме добавления аннотаций типов, вы можете документировать функции.

/**
 * Повторяет текст заданное количество раз
 *
 * @param {string} text - Текст
 * @param {number} count - Количество повторений
 */

function repeat(text, count) {
  return Array(count + 1).join(text)
}

Потренируемся в документировании.

Документирование параметров

Опциональные типы

Чтобы показать опциональность типа, добавьте после него знак равенства. В примере ниже number= — то же самое, что и number | null | undefined. Такой синтаксис можно использовать только в типах JSDoc.

/**
 * @param {string} text
 * @param {number=} count
 */

function repeat(text, count = 1) {
  // ...
}

Документируем опции

Вы можете документировать свойства параметров, например, options.count или options.separator. Эту возможность можно использовать для документирования props в функциональных компонентах React.

/**
 * @param {string} text - Text to repeat
 * @param {Object} options
 * @param {number} options.count
 * @param {string} options.separator
 */

function repeat(text, options) {
  console.log(options.count)
  console.log(options.separator)
  // ...
}

repeat('hello', { count: 2, separator: '-' })

Утверждения типов (Type Assertions)

Переменные

Используйте @type, когда пишете инлайн определение для аргументов функций. Это обычно избыточно для констант, так как TypeScript чётко работает с типами. Подход полезен при работе с изменяемыми данными, например, с переменными.

/**
 * Time out in seconds.
 * @type number
 */

let timeout = 3000

Параметры функций

@type можно использовать для определения типов аргументов функций инлайн. Это особенно удобно при работе с анонимными функциями.

list.reduce((
 /** @type number */ acc,
 /** @type number */ item
) => {
  return acc + item
}, 0)

Далее поговорим о выносе определений типов в отдельные файлы.

Импорт определений типов

Импортируем типы

Сложные и переиспользуемые типы лучше определять во внешних файлах. Они имеют расширение .d.ts. Обратите внимание, это должны быть именно файлы TypeScript. Импортировать определения из файлов JavaScript невозможно.

Типы можно импортировать с помощью представленного ниже синтаксиса. Определения должны определяться во внешних файлах с расширением .d.ts, как сказано выше.

/** @typedef { import('./myTypes').User } User */

/**
 * @param {User} author
 */

function cite(author) {
  // ...
}

Определяем типы во внешних файлах

Ниже представлен синтаксис определения типов во внешних файлах TypeScript. Ещё раз обратите внимание, импортировать определения типов из файлов JavaScript невозможно.

/* myTypes.d.ts */
export interface User {
  name: string
  email: string
}

Теперь разберёмся, можно ли определять типы в JavaScript-файлах.

Определение типов в файлах JavaScript

Типы объектов

Для определения типов объектов используйте @typedef. Предпочтительно делать это во внешних файлах с расширением .d.ts. Но вы можете использовать представленный ниже синтаксис и в файлах JavaScript.

/**
 * @typedef {Object} Props
 * @property {string} title - The title of the page
 * @property {number} updatedAt - Last updated time
 */

/**
 * A component.
 *
 * @param {Props} props
 */

const ArticleLink = props => {
  console.log(props.title)
  console.log(props.updatedAt)
  // ...
}

Объединение типов

Используйте объединение типов (|) для определения двух или более возможных вариантов. Для простоты используйте @typedef.

/** @typedef {number | string} NumberOrString */

Как насчёт React?

Определение типов в React

Функциональные компоненты

Функциональные компоненты представляют собой функции. Поэтому вы можете документировать их способами, о которых говорилось выше в разделе о документировании функций. В следующем примере показано документирование с помощью типов объектов.

/**
 * This is a React function component.
 *
 * @param {Object} props
 * @param {string} props.title
 * @param {string} props.url
 * @param {string} props.image
 */

const ArticleLink = props => {
  // ...
}

Подробности о функциональных компонентах можно узнать в курсе по React, который входит в профессию «Фронтенд JavaScript».

Компоненты на классах

Используйте @extends для определения типов props и state. Также для решения этой задачи можно использовать @typedef инлайн или с импортом.

/**
 * This is a React class component.
 *
 * @extends {React.Component<Props, State>}
 */

class MyComponent extends React.Component {
  // ...
}

Расширенные возможности

Синтаксис JSDoc не такой выразительный, как TypeScript, но эти инструменты всё-таки похожи. Ниже перечислены некоторые дополнительные возможности TS, доступные в JSDoc.

  • Темплейты — @templates.
  • Возврат значений — @returns.
  • Условия типов — @returns.
  • Функциональные типы — @callback.
  • Перечисления — @enum.

Ещё больше возможностей найдёте в официальной документации.

Резюме

Ниже представлены перечисленные в статье способы работы с аннотациями типов.

Проверка типов JavaScript

// @ts-check

Документирование функций

/**
 * Multiply a number by itself.
 * @param {number} n - What to square
 */

function square(n) {
  // ...

Импорт определений типов (позволяет определять типы во внешних файлах)

/** @typedef { import('./myTypes').User } User */

Опциональные типы

/** @param {User=} user */

Анонимные функции

numbers.map((/** @type number */ n) => {
  return n * 2
})

Документирование свойств параметров объектов

/**
 * @param {Object} options
 * @param {number} options.count
 * @param {string} options.sep
 */

function repeat(options) {
  // ... options.count, options.sep

Адаптированный перевод статьи Type annotations in JavaScript files by Rico Sta. Cruz. Мнение администрации Хекслета может не совпадать с мнением автора оригинальной публикации.

Аватар пользователя Дмитрий Дементий
Дмитрий Дементий 21 февраля 2020
Рекомендуемые программы

С нуля до разработчика. Возвращаем деньги, если не удалось найти работу.

Иконка программы Фронтенд-разработчик
Профессия
Разработка фронтенд-компонентов веб-приложений
1 декабря 8 месяцев
Иконка программы Python-разработчик
Профессия
Разработка веб-приложений на Django
1 декабря 8 месяцев
Иконка программы PHP-разработчик
Профессия
Разработка веб-приложений на Laravel
1 декабря 8 месяцев
Иконка программы Node.js-разработчик
Профессия
Разработка бэкенд-компонентов веб-приложений
1 декабря 8 месяцев
Иконка программы Верстальщик
Профессия
Вёрстка с использованием последних стандартов CSS
в любое время 5 месяцев
Иконка программы Java-разработчик
Профессия
Разработка приложений на языке Java
1 декабря 10 месяцев
Иконка программы Разработчик на Ruby on Rails
Профессия
Новый
Создает веб-приложения со скоростью света
1 декабря 5 месяцев