Avatar ·

Что такое файлы *.d.ts в TypeScript и зачем они нужны?

Всем привет! Я начал изучать TypeScript недавно и столкнулся с непонятной для меня вещью. В проектах я часто вижу файлы с расширением `.d.ts`. Например, есть папка `node_modules`, и там внутри библиотек лежат такие файлы. Я открыл один из них, и там было что-то вроде: ```typescript declare module 'lodash' { export function chunk(array: T[], size?: number): T[][]; } ``` Я не совсем понимаю, что это такое. Это что, какой-то отдельный вид TypeScript-файлов? Зачем они нужны, если у нас есть обычные `.ts` файлы? Я пробовал сам создать такой файл и написать там какой-то код, но компилятор ругается, когда я пытаюсь там объявить переменные без ключевого слова `declare`. Ещё я заметил, что если я пишу `import` из библиотеки, у которой нет таких файлов, то TypeScript выдаёт ошибку "Cannot find module". Получается, что эти `.d.ts` файлы как-то помогают TypeScript понимать, какие типы есть в обычном JavaScript коде? Буду благодарен за подробное объяснение, желательно с примерами. <<>>

Что такое файлы декларации типов (*.d.ts)?

Файлы с расширением .d.ts — это файлы декларации типов (type declaration files) в TypeScript. Они не содержат исполняемого кода, а только описывают структуру и типы существующего JavaScript (или TypeScript) кода. Представьте их как "контракты" или "спецификации", которые говорят компилятору TypeScript: "Вот такой-то модуль существует, и у него есть такие-то функции, классы и переменные с такими-то типами".

Основные отличия от обычных .ts файлов

  • .ts файлы — содержат и типы, и реализацию (код). Они компилируются в JavaScript.
  • .d.ts файлы — содержат только объявления типов. Они не компилируются в JS, а используются только для проверки типов и автодополнения в IDE.

Зачем они нужны?

Основная причина — работа с обычным JavaScript кодом. TypeScript — это надстройка над JavaScript, и он не может "заглянуть" в обычный JS-файл, чтобы узнать его типы. Файлы .d.ts решают эту проблему:

  • Для внешних библиотек (например, Lodash, jQuery, React). Большинство популярных библиотек имеют готовые декларации, которые можно установить через npm install @types/название_библиотеки.
  • Для вашего собственного JS кода, который вы постепенно переводите на TypeScript. Вы можете написать .d.ts файлы для существующих JS-модулей, чтобы получить типизацию без переписывания всего кода.
  • Для описания глобальных переменных (например, window.MY_APP_CONFIG).

Как это работает на практике?

Рассмотрим пример. Допустим, у вас есть библиотека my-calculator.js:

// my-calculator.js
function add(a, b) {
  return a + b;
}
function multiply(a, b) {
  return a * b;
}
module.exports = { add, multiply };

Чтобы TypeScript понимал типы этой библиотеки, вы создаёте файл my-calculator.d.ts в той же папке:

// my-calculator.d.ts
declare module 'my-calculator' {
  export function add(a: number, b: number): number;
  export function multiply(a: number, b: number): number;
}

Теперь в вашем TypeScript-файле вы можете писать:

import { add, multiply } from 'my-calculator';

const result = add(5, 3); // result: number — TypeScript знает тип!
const bad = add("hello", 5); // Ошибка! TypeScript видит, что аргумент должен быть number

Ключевые конструкции внутри .d.ts

  • declare — ключевое слово, которое говорит "это объявление существует, но реализация где-то в другом месте".
  • declare module 'имя_модуля' — описывает целый модуль.
  • declare namespace MyNamespace — описывает пространство имён.
  • declare function, declare class, declare var — описывают отдельные сущности.
  • interface и type — можно использовать без declare, они и так только для типов.

Как создавать свои .d.ts файлы?

  1. Создайте файл с расширением .d.ts (например, globals.d.ts).
  2. Если вы описываете глобальные переменные, просто используйте declare:
    // globals.d.ts
    declare const API_URL: string;
    declare function trackEvent(eventName: string, data?: object): void;
  3. Если вы описываете модули, используйте declare module:
    // my-types.d.ts
    declare module '*.jpg' {
      const src: string;
      export default src;
    }

Помните: .d.ts файлы не заменяют .ts файлы. Они — мост между миром JavaScript и строгой типизацией TypeScript. Без них вы не сможете нормально работать с большинством JS-библиотек в TypeScript-проекте.

<<>>

Автоматическая генерация .d.ts файлов

Если вы пишете свой проект на TypeScript, вам не обязательно создавать .d.ts файлы вручную. Компилятор TypeScript может генерировать их автоматически из ваших .ts файлов! Это полезно, когда вы создаёте библиотеку для других разработчиков — они получат и готовый JavaScript, и файлы декларации типов.

Достаточно указать в tsconfig.json опцию "declaration": true:

{
  "compilerOptions": {
    "declaration": true,
    "outDir": "./dist"
  }
}

После компиляции в папке dist появятся файлы .d.ts рядом с .js файлами. Например, если у вас есть src/utils.ts:

export function greet(name: string): string {
  return `Hello, ${name}!`;
}

То в dist появится utils.d.ts:

export declare function greet(name: string): string;

Этот подход гарантирует, что ваши декларации всегда синхронизированы с кодом. Для больших проектов ручное написание .d.ts — это устаревшая практика, которая использовалась в основном для "обёртывания" существующих JS-библиотек.

Совет: Если вы используете готовую JS-библиотеку без типов, сначала проверьте npm install @types/имя_библиотеки. Только если такого пакета нет, имеет смысл писать свой .d.ts файл.