*.d.ts
Что такое *.d.ts файлы и когда их нужно писать
*.d.ts файлы - это файлы декларации типов. Они содержат описание типов без реализации. Например, сигнатуры функций без тела, название и тип глобальных переменных без значений. В основном файлы декларации типов нужны для написания библиотек. Они нужны тогда, когда:
вы написали библиотеку и хотите, чтобы ее можно было использовать не только в TypeScript проектах
вы хотите использовать библиотеку, которая написана на JavaScript.
Рассмотрим ситуацию. Вы написали библиотеку для работы с математическим представлением вектора.
Если выложить этот код в качестве библиотеки (например, сделать и опубликовать npm-пакет), то этим кодом смогут пользоваться только проекты с настроенным TypeScript. Более того, возможно потребуется дополнительная настройка TypeScript, чтобы при компиляции проекта он компилировал и файлы нашей библиотеки.
Другой способ публикации библиотеки - скомпилировать TypeScript в JavaScript и выложить уже JavaScript файлы. В таком случаи этой библиотекой могут пользоваться любые проекты, как обычной библиотекой на JavaScript. Однако, если эту библиотеку планируется использовать в TypeScript проекте - хотелось бы сохранить типизацию. Здесь и появляются .d.ts файлы. Перед публикацией библиотеки мы компилируем TypeScript в JavaScript, но конфигурируем компилятор так, чтобы рядом с получившимися .js файлами, он создал .d.ts файлы по каждому файлу JavaScript-а. Далее мы публикуем и .js файлы и .d.ts файлы. Теперь, если использовать эту библиотеку в JavaScript проекте, то будут просто использоваться .js файлы, если использовать в TypeScript проекте, то при компиляции будут использоваться .d.ts, а runtime пред компилированные .js.
Синтаксис декларации типов
*.d.ts файлы можно получить автоматически или написать вручную. Для автоматической генерации нужно, чтобы библиотека изначально был на TypeScript и компилятор был настроен на генерацию файлов декларации. Например, для кода выше компилятор сгенерирует такие декларации:
Если библиотека изначально написана на JavaScript (или на другом языке, но не на TypeScript) или автоматическая генерация деклараций типов по TypeScript-файлам по каким-то причинам не устраивает, то файлы деклараций можно написать вручную. Возможно есть сторонние генераторы *.d.ts файлов по JavaScript, TypeScript и другим языкам, но их мы рассматривать не будем.
Одно из главных ключевых слов в файлах деклараций - это слово declare
. Используя это слово в какой-либо синтаксической конструкции (например, в объявлении класса), мы указываем TypeScript-у, что ее нужно интерпретировать, как декларацию. Рассмотрим два блока кода выше. При описании класса в *.ts файле мы описывали всю сигнатуру класса, правила инициализации полей, тела конструктора и методов и модификаторы доступа. В файле декларации класс помечен словом declare
и у него описан лишь публичный интерфейс взаимодействия с этим классом без реализации - что и с какими параметрами можно вызывать, что в итоге получится, а также к каким полям и методам есть доступ.
Рассмотрим автоматическую генерацию файлов декларации и то, как ее можно изменять. Если объявлены глобальные переменные
то в их декларациях используется declare
и сохраняется способ объявления, но теряется значение - оно с точки зрения проверки на типы не важно:
Однако, если явно не указывать тип переменных, то файл декларации немного изменится:
Для переменной объявленной с использованием const
автоматический вывод типов может вывести литеральный тип.
Для декларации функций нужно указать их сигнатуры - название, параметры и их типы и возвращаемое значение.
Если функция использует generic-и, то в декларации нужно указать и generic-параметры и их ограничения.
Для объявления интерфейсов и type alias-ов ключевое слово declare
можно опускать.
Для декларации классов нужно использовать особенности декларации переменных и функций. По их подобию сделана декларация полей, методов и конструктора. Ключевое слово declare
используется только у самого класса. Поля декларируются со всеми модификаторами, но без инициализации. Методы также декларируются со всеми модификаторами и описанной сигнатурой, но без тела.
Публикация типов
В современном мире существует 2 способа публикации TypeScript типов.
Первый способ - включить .d.ts файлы прямо в библиотеку с .js файлами. Это может быть сделано по разному: можно каждый .d.ts файл хранить рядом с каждым соответствующим .js файлом, а можно внести все .d.ts файлы в отдельную директорию или "сбандлить" в один файл. Преимущество такого подхода в том, что пользоваться этой библиотекой в TypeScript проекте можно "из коробки". Недостаток - .d.ts файлы добавляют размер библиотеке. Если проект не использует TypeScript, то .d.ts файлы ему не нужно. Но из-за того что они встроены в библиотеку, они всегда будут приходить вместе с ней.
Второй способ - выделить типы в отдельную библиотеку. В современном TypeScript сообществе существует подход вынесения типов библиотек в отдельный пакет. Эти пакеты типов хранятся в специальном репозитории: https://github.com/DefinitelyTyped/DefinitelyTyped. В этом репозитории хранятся типы для многих популярных библиотек. Например, здесь хранятся типы для React
. Типы из этой библиотеки публикуются в npm с префиксом @types/
. Например, типы для React
находятся в npm-пакете @types/react
. Не обязательно выносить типы своей библиотеки в это репозиторий. Это лишь договоренность. Можно выносить свои типы в отдельный пакет с другим именем. В таком случаи нужно четко объяснить пользователю библиотеки в каком пакете они лежат. Преимущество этого подхода в том, что можно подключать типы тогда, когда они нужны. Недостаток - нужно управлять двумя (или более) пакетами. Если обновили саму библиотеку, нужно не забыть обновить типы. Типы могут не актуальными или обновляться с задержкой.
Задания
Предположим мы написали библиотеку для работы с векторами на JavaScript. Теперь нужно написать TypeScript-типы для этой библиотеки. Библиотека состоит из одного файла: vector.js.
Last updated