Declaration files (.d.ts)
Файлы деклараций -- описание типов для JS-библиотек без исходников на TS.
Зачем нужно
- Типизация сторонних JS-библиотек
- Автодополнение и проверка типов при использовании npm-пакетов
- Публикация типов для своей библиотеки
Где используется
- Подключение JS-библиотек в TS-проект, написание npm-пакетов
Как работает
TypeScript ищет типы в таком порядке:
.tsфайл рядом с импортом"types"поле вpackage.jsonбиблиотеки@types/имя-пакетаиз DefinitelyTyped- Ручной
.d.tsфайл
Установка типов
npm i -D @types/lodash
npm i -D @types/express
npm i -D @types/node
Написание своего .d.ts
// global.d.ts -- расширение глобальных типов
declare global {
interface Window {
__APP_VERSION__: string;
}
}
export {};
// module.d.ts -- декларация модуля
declare module 'my-lib' {
export function doSomething(input: string): number;
export interface Config {
debug: boolean;
timeout: number;
}
}
// ambient declaration для CSS modules
declare module '*.module.css' {
const classes: Record<string, string>;
export default classes;
}
Генерация .d.ts из TS
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./dist/types",
"emitDeclarationOnly": true
}
}
npx tsc --emitDeclarationOnly
Альтернативная позиция: JS-файл + рядом .d.ts
"Программируйте на TypeScript как на C++: код — отдельно, заголовки (.d.ts) — отдельно."
Параллель с Delphi (PAS+DFM) и C++ (.cpp+.h). Автор TS — Андерс Хейлсберг — создал и Delphi, и C#, но почему-то не принёс культуру разделения в TS.
// units.js — реализация на чистом JS
export const bytesToSize = (bytes) => { /* ... */ };
// units.d.ts — контракт рядом
export function bytesToSize(bytes: number): string;
Почему это лучше для больших проектов
- Контракт компактно — весь API EventEmitter помещается на один экран в
.d.ts. Без.d.tsнужно листать десятки страниц кода. - Читая типы — видишь контракт. Реализация не отвлекает.
- Менее точная типизация — это ок. В TS-файле типы должны быть максимально точны (они привязаны к коду). В
.d.tsможно описать только то, что вызывающий должен знать. - JS работает без сборки. TS-проверка — отдельный шаг пайплайна.
Обязательные настройки
{
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"noEmit": true, // КРИТИЧНО — иначе перезапишет ваш JS
"declaration": false
}
}
Подводные камни
- Конфликты имён. Если у вас есть и
units.ts, иunits.js+units.d.ts— TS запутается. Выбирайте один путь на модуль. - Гранулярность.
.d.tsможно делать на файл, на папку (черезindex.d.ts) или на весь проект (один глобальный). - Достаточно типизировать 2-3 ключевых идентификатора. Не нужно покрывать всё.
Связанные темы
Источники
- 🎓 TypeScript vs JavaScript: как лучше писать типы · 2025-11-08 · YouTube
- Позиция автора: для больших проектов — JS + .d.ts, по образцу .h в C++.