Файлы объявлений TypeScript

Файл объявлений — этопереводчик между TypeScript и библиотеками JavaScript, который сообщает TypeScript, какие функции предоставляет библиотека JavaScript, какие типы у параметров и какие типы у возвращаемых значений.


Начнём с проблемы.

Предположим, вы пишете проект на TypeScript и вам нужно подключить стороннюю библиотеку JavaScript (например, jQuery). Вы можете написать такой код:

$('#foo');
// или 
jQuery('#foo');

Этот код прекрасно работает в чистом проекте JavaScript, но в файле TypeScript он сразу вызовет ошибку:

jQuery('#foo');

// index.ts(1,1): error TS2304: Cannot find name 'jQuery'.

Почему возникает ошибка? Потому что TypeScript не распознаёт$иjQueryчто это такое.

Основная особенность TypeScript — проверка типов: ему нужно знать тип каждой переменной и каждой функции во время компиляции. Но jQuery — это чистая библиотека JavaScript без информации о типах, поэтому TypeScript, естественно, не может её понять.


Быстрое решение: ключевое слово declare

Самый простой способ — использовать ключевое словоdeclare, чтобы вручную сообщить TypeScript: «Эта переменная существует, и её тип таков»:

declare var jQuery: (selector: string) => any;

jQuery('#foo');

Смысл этой строки кода таков: объявить переменнуюjQuery, которая является функцией, принимающей параметр типаstring, а возвращаемое значение может быть любого типа (any)。

Теперь TypeScript не будет сообщать об ошибке, потому что компилятор уже знает, какой тип у jQuery.

declareТипы, объявленные с помощью ключевого слова, действуют только на этапе компиляции; они полностью удаляются из скомпилированного кода JavaScript и не влияют на поведение во время выполнения.

Скомпилированный код JavaScript приведённого выше примера выглядит так:

jQuery('#foo');

Как видите, объявлениеdeclareисчезло, остался только фактический код вызова.

Ноdeclareможет решить только временную проблему отдельного файла. Если в библиотеке много методов и много классов, очевидно, нереально вручную писать declare в каждом файле. Здесь на помощь приходят файлы объявлений.


Файлы объявлений: решение раз и навсегда

Файл объявлений помещает все объявленияdeclareв один отдельный файл, и любой TypeScript-файл в проекте может ссылаться на него.

Соглашения об именовании файлов

Файлы объявлений единообразно используют.d.tsв качестве суффикса,dчто означает «declaration». Например:

example.d.ts

Базовый синтаксис

Синтаксис объявления модуля выглядит следующим образом:

declare module Module_Name {
}

В файле TypeScript используйте директиву с тремя слэшами, чтобы подключить файл объявлений:

/// <reference path = "example.d.ts" />

Директива с тремя слэшами — это специфичный для TypeScript синтаксис, используемый, чтобы сообщить компилятору о необходимости включить указанный файл объявлений во время компиляции.

Файлы объявлений для многих популярных сторонних библиотек (таких как jQuery, Lodash) уже поддерживаются сообществом и хранятся вDefinitelyTypedпроект. Вам просто нужно установить соответствующий пакет@types/xxxчерез npm, и вы сможете использовать его, не прописывая типы вручную.


Полный пример: создание файлов объявлений с нуля

Следующий полный пример демонстрирует весь процесс создания и использования файла объявлений.

Весь процесс включает следующие файлы:

ФайлНазначение
CalcThirdPartyJsLib.jsСторонняя библиотека JavaScript (чистый JS, без информации о типах)
Calc.d.tsФайл объявлений (написан вручную, описывает типы библиотеки)
CalcTest.tsБизнес-код на TypeScript (ссылается на файл объявлений, вызывает библиотеку)
CalcTest.jsСкомпилированный результат (JS-файл, скомпилированный с помощью tsc)
example.htmlФинальная страница, работающая в браузере

Шаг 1: Создание сторонней библиотеки JavaScript

Предположим, у нас есть сторонняя библиотека, предоставляющая функциональность кумулятивного суммирования. Она использует пространство имёнExampleдля организации кода и предотвращения конфликтов имён переменных:

Код файла CalcThirdPartyJsLib.js:

// Путь к файлу: CalcThirdPartyJsLib.js
// Это имитация сторонней библиотеки JavaScript

// Объявить переменную пространства имён Example (создать пустой объект, если она не существует)
var Example;

// Используйте немедленно вызываемое функциональное выражение (IIFE), чтобы инкапсулировать код и предотвратить утечку внутренних переменных в глобальную область видимости
(function(Пример) {
    // Конструктор Calc, используемый для создания объектов калькулятора
    var Calc = (function () {
        function Calc() {
            // Пока параметры инициализации не нужны; оставьте конструктор для будущего расширения
        }
    })

    // Метод doSum: вычисляет сумму всех целых чисел от 0 до limit
    // limit (обязательный): верхняя граница суммы включительно
    // Пример: при limit=10 вычисляется 0+1+2+...+10 = 55
    Calc.prototype.doSum = function (limit) {
        var sum = 0;

        for (var i = 0; i <= limit; i++) {
            sum = sum + i;
        }
        return sum;
    }

    // Прикрепите конструктор Calc к пространству имён Example
    // Таким образом, извне можно создавать экземпляры через new Example.Calc()
    Example.Calc = Calc;
    return Calc;
})(Example || (Example = {}));

// Внутренний код самотестирования библиотеки
var test = new Example.Calc();

Эта библиотека использует распространённый шаблон: немедленно вызываемое функциональное выражение (IIFE). Проще говоря, оно оборачивает код в функцию и сразу его выполняет, поэтому переменные, определённые внутри функции, не утекают наружу, что позволяет избежать конфликтов имён с другим кодом.

Шаг 2: Напишите файл декларации

Теперь у нас есть библиотека JS, но у неё нет информации о типах. Нам нужно создать файл декларации, который описывает только «форму» библиотеки — какие есть классы, какие есть методы, какие типы у параметров и возвращаемых значений — но не содержит никакой фактической логики кода:

Код файла Calc.d.ts:

// Путь к файлу: Calc.d.ts
// Это файл декларации; он содержит только информацию о типах и не содержит исполняемого кода

// Объявите модуль Example, соответствующий пространству имён Example в библиотеке JS
declare module Example {
   // Объявите класс Calc, сообщая TypeScript, что этот класс можно создать с помощью new
   export class Calc {
      // Объявите метод doSum: принимает параметр number и возвращает number
      // Примечание: здесь объявлена только сигнатура метода, без тела метода (фигурных скобок)
      doSum(limit: number): number;
   }
}

Самое большое различие между файлом объявления и обычным файлом .ts: файл объявления содержит только сигнатуры типов, без кода реализации. Он отвечает только на вопрос "как выглядит эта функция", а не "что делает эта функция".

Шаг 3: Используйте это в коде TypeScript

Теперь напишите бизнес-код. После подключения файла объявления вы можете использовать эту стороннюю JS-библиотеку так же, как нативную библиотеку TypeScript:

Код файла CalcTest.ts:

// Путь к файлу: CalcTest.ts
// Директива с тремя косыми чертами: указывает компилятору TypeScript включить файл объявления
/// <reference path = "Calc.d.ts" />

// Создайте экземпляр Calc; теперь TypeScript может правильно определить тип obj
var obj = new Example.Calc();

// obj.doSum("Hello"); // Ошибка компиляции! "Hello" — строка, но doSum требует аргумент типа number
console.log(obj.doSum(10)); // Правильный вызов: передайте 10, ожидается 55

Обратите внимание на эту закомментированную строку:

obj.doSum("Hello");

Если вы раскомментируете эту строку, TypeScript сообщит об ошибке во время компиляции, потому что файл объявления уже указывает, что doSum принимает только параметр типа number. Это проверка типов защищает вас — ошибки выявляются во время написания кода, а не приводят к сбою во время выполнения в браузере.

Шаг 4: Компиляция TypeScript

Используйте встроеннуюtscкоманду для компиляции:

tsc CalcTest.ts

После компиляции будет сгенерированCalcTest.jsфайл со следующим содержимым:

Скомпилированный вывод CalcTest.js:

// Путь к файлу: CalcTest.js (автоматически создан командой tsc)
/// <reference path = "Calc.d.ts" />
var obj = new Example.Calc();
//obj.doSum("Hello"); // Ошибка компиляции
console.log(obj.doSum(10)); // Вывод: выводит 55 в консоль

Видно, что директивы с тройной косой чертой и информация о типах в файлах объявлений исчезли из скомпилированного вывода, оставив только чистый код времени выполнения JavaScript.

Шаг 5: Запуск в браузере

Наконец, создайте HTML-страницу, чтобы связать все JS-файлы вместе:

Пример

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Пример руководства (example.com)</title>
<!-- Шаг 1: Загрузите стороннюю библиотеку, чтобы сделать пространство имён Example доступным глобально -->
<script src = "CalcThirdPartyJsLib.js"></script>
<!-- Шаг 2: Загрузите скомпилированный бизнес-код -->
<script src = "CalcTest.js"></script>
</head>
<body>
    <h1>Тест файла объявлений</h1>
    <p>Давайте попробуем.</p>
</body>
</html>

Откройте этот HTML-файл в браузере, откройте консоль (F12), и вы увидите вывод:

55

Это возвращаемое значение doSum(10): 0+1+2+...+10 = 55.

声明文件测试结果


Итог

Файл объявлений — это по сути «руководство по типам», которое позволяет TypeScript понимать и проверять чистые библиотеки JavaScript.

Весь рабочий процесс можно свести к трём шагам:

1. Получите JS-библиотеку и проанализируйте, какие API она предоставляет.

2. Напишите.d.tsфайл декларации, описывающий сигнатуры типов этих API.

3. Ссылайтесь на файл декларации в коде TypeScript, чтобы получить полную защиту проверки типов.

Для часто используемых сторонних библиотек в повседневной разработке у подавляющего большинства уже есть готовые файлы деклараций (устанавливаются с помощьюnpm install @types/xxx). Только когда вы используете очень малоизвестную библиотеку или внутреннюю приватную библиотеку, вам нужно вручную писать файлы деклараций.

Другие расширения