Что за файлы d ts

Обновлено: 03.07.2024

Декларации это очень важная часть TypeScript благодаря которой магия статической типизации проецируется на динамический JavaScript. Поэтому декларациям будет посвящена вся данная глава, рекомендуемая тем, кто только собирается писать свою первую типизированную библиотеку, которую планируется распространять с помощью npm репозитория.

Что такое декларация (Declaration)

Поскольку при разработке программ на TypeScript используются библиотеки написанные на JavaScript, компилятор tsc, чьей главной задачей является проверка типов, чувствует себя будто у него завязаны глаза. Несмотря на то, что с каждой новой версией вывод типов все лучше и лучше учится разбирать JavaScript, до идеала ещё далеко. Кроме того, разбор JavaScript кода добавляет нагрузку на процессор, драгоценного время которого при разработке современных приложений, порой и так не достаточно.

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

Еще не забыты дни, когда для часто используемых библиотек приходилось писать декларации вручную, при чем они часто содержали ошибки. Кроме этого, декларации не успевали обновляться под постоянно развивающиеся библиотеки. Сейчас такие проблемы кажутся уже нереальными, но несмотря на это, до сих пор приходится прибегать к использованию менеджера деклараций, который был создан в те самые далекие времена.

Установка деклараций с помощью @types

Если декларация распространяется отдельно от библиотеки, то она скорее всего, попадет в огромный репозиторий на github под названием DefinitelyTyped содержащий огромное количество деклараций. Чтобы было проще ориентироваться в этом множестве, помимо сайта "TypeSearch" выступающего в роли поисковика, был создан менеджер деклараций под названием Typed. Но о нем мы говорить не будем поскольку он применяется при работе с TypeScript версии меньше чем v2.0, поэтому речь пойдет о его развитии в образе команды пакетного менеджера npm, а именно @types.

Для того, что бы установить требующуюся декларацию, в терминале необходимо выполнить команду, часть которой состоит из директивы @types , после которой через косую черту / следует имя библиотеки.

Для примера, воспользуемся проектом созданным в теме посвященной настройки рабочего окружения и для демонстрации работы директивы @types установим всем известную библиотеку React.

Первым делом установим саму библиотеку React выполнив в терминале, запущенным из-под директории проекта, следующую команду.

Открыв директорию /node_modules/ можно убедиться, что библиотека React успешно установлена, поэтому сразу же попытаемся импортировать её в файл index.js расположенным в директории src, предварительно изменив его расширение на требуемое для работы с React — .tsx .

Несмотря на установленную на предыдущем шаге библиотеку React, при попытке импортировать её модули возникла ошибка. Возникла она потому, что компилятору TypeScript ничего не известно о библиотеке React, поскольку декларация описывающая типы поставляется отдельно от неё. Чтобы tsc понял, что от него хотят, требуется дополнительно установить декларацию при помощи команды @types пакетного менеджера npm .

Ошибка, возникающая при импорте модулей React исчезла, а если заглянуть в директорию _/node_modules/ , то можно увидеть новую примечательную поддиректорию /@types предназначенную для хранения устанавливаемых с помощью опции @types декларации.

Но для полноты картины и этого недостаточно. Для того, что бы добавить наш компонент в dom-дерево, необходимо установить ReactDOM, который уже давно развивается отдельной библиотекой.

Кроме того, нужно установить необходимую для работы с ним декларацию.

Осталось только активировать опцию --jsx в _tsconfig.json и скомпилировать проект, как это было показано ранее.

Подготовка к созданию декларации

Помимо того, что декларацию можно написать руками, её также можно сгенерировать автоматически, при условии, что код написан на TypeScript. Для того, что бы tsc при компиляции генерировал декларации, нужно активировать опцию компилятора --declaration .

Будет не лишним напомнить, что декларацию нужно генерировать только тогда, когда библиотека полностью готова. Другими словами, активировать опцию --declaration нужно в конфигурационном файле production сборки. Кроме того, в декларации нуждается только код, который будет собран в подключаемую библиотеку. Поэтому точкой входа в библиотеку должен быть файл, который содержит только импорты нужных модулей. Но разработка библиотеки невозможна без её запуска, а значит и точки входа в которой будет создан и инициализирован её экземпляр. Поэтому, что бы избежать чувства «что-то пошло не так», необходимо помнить, что при создании библиотеки требующей декларацию, в проекте может быть несколько точек входа. Точкой входа самого компилятора, служит конфигурационный файл который ему был установлен при запуске. Это означает, что если проект находится в директории src , то в декларации путь будет указан как src/libName вместо требуемого lib .

Это в свою очередь означает, что при импорте модулей придется учитывать лишнюю директорию.

Это проблему можно решить, разместив конфигурационный файл в директории исходного кода, в нашем случае это директория src . Кто-то не придаст этому значение, кому-то это может показаться неэстетичным. Поэтому при рассмотрении генерации деклараций с помощью tsc, конфигурационный файл будет лежать непосредственно в директории src . Но при рассмотрении генерации деклараций с помощью сторонних библиотек, будет освещен альтернативный вариант.

Но и это ещё не все. Представьте, что Вы создаете библиотеку React, которая в коде представляется одноимённым классом расположенном в файле React.ts . При этом модуль, который будет представлять вашу библиотеку должен называться react , что в свою очередь обязывает задать имя файлу являющегося точкой входа как `react.js. Ну и, что спросите вы? Если вы ещё не знаете ответ на этот вопрос, то будете удивлены, узнав, что существуют операционные системы, как, например, Windows, которые расценивают пути до файлов React.ts и react.ts идентичными. Простыми словами если в директории присутствует файл с идентификатором Identifier, то ОС просто не позволит создать одноимённый файл, даже если его символы будут отличаться регистром. Именно об этом и будет сказано в ошибке, возникающей когда TypeScript обнаружит одноимённые файлы в одной директории. Кроме того, если ваша операционная система позволяет создавать файлы чьи идентификаторы отличаются только регистром, помните, что разработчик работающий с вами в одной команде не сможет даже установить проект себе на машину, если его операционная система работает по другим правилам.

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

И поскольку TypeScript является компилируемым языком, не будет лишним напомнить правила именования директории в которую будет компилироваться результат. В случае разработки приложения, директорию содержащую скомпилированный результат принято называть dest (сокращение от слова destination). При разработке внешней библиотеки или фреймворка, директорию для собранных файлов принято называть dist (сокращение от слова distributive).

Разновидности деклараций

На самом деле это глава должна называться «разновидности библиотек», так как именно о них и пойдет речь. Дело в том, что совсем недавно вершиной хорошего тона считалось объединение всего кода в один файл. Это же правило соблюдалось и при создании библиотек. Но сейчас все кардинально поменялось, и дело вот в чем.

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

Tree Shaking — это механизм позволяющий включать в сборку исключительно используемый код. Простыми словами, данный механизм позволяет взять только используемую часть от всей библиотеки. В перспективе это должно быть спасением, но на деле оказалось не совсем так.

Дело в том, что на данный момент Tree Shaking работает только если библиотека разбита на множество модулей. К примеру такие именитые библиотеки, как lodash или rxjs, для каждой отдельной функции создают отдельную точку входа, что при их использовании позволят значительно сократить размер конечного кода. Обозначим подобные библиотеки, как библиотеки с множеством точек входа. Кроме того, существуют библиотеки сопоставимые с монолитом, поскольку при использовании их малой части в конечную сборку они попадают целиком. Обозначим такие библиотеки, как библиотеки с единственной точкой входа.

Декларации и область видимости

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

Для установки связи с внешними файлами скриптов javascript в TS служат декларативные или заголовочные файлы. Это файлы с расширением .d.ts , они описывают синтаксис и структуру функций и свойств, которые могут использоваться в программе, не предоставляя при этом конкретной реализации. Их действие во многом похоже на работу файлов с расширением .h в языках C/C++. Они выполняют своего рода роль оберток над библиотеками JavaScript.

Рассмотрим, как мы можем использовать заголовочные файлы. Иногда в программах на javascript используются глобальные переменные, которые должны быть видны для всех функций приложения. Например, пусть на веб-странице (или во внешнем подключаемом файле javascript) в коде js определена переменная:

В данном случае для простоты переменная определена веб-странице, хотя она также могла быть определена во внешнем подключенном js-файле.

И, допустим, мы хотим использовать эту переменную message в коде TypeScript в файле app.ts:

При запуске приложения компилятор TS не сможет скомпилировать программу, так как для кода TS глобальная переменная пока не существует. В этом случае нам надо подключать определение глобальной переменной с помощью декларативных файлов. Для этого добавим в проект новый файл, который назовем globals.d.ts и который будет иметь следующее содержимое:

С помощью ключевого слова declare в программу на TS подключается определение глобальной переменной.

То есть у нас получится следующая структура проекта:

Компиляция

Если мы компилируем, передавая компилятору в консоли название файла:

То в этом случае компилятор не найдет автоматически файл globals.d.ts. В этом случае нам надо в файле app.ts явно указать расположение файла globals.d.ts с помощью директивы reference

Заголовочные файлы в TypeScript

Если же мы полагаемся на файл конфигурации tsconfig.json, просто выполняя команду

то директиву /// <reference path="globals.d.ts" /> можно не указывать.

Подобным образом мы можем подлюкчать другие компоненты кода JavaScript - функции, объекты, классы. Рассмотрим их подключение.

Функции

Пусть на веб-странице в коде js объявлены две следующие функции:

Функция hello() выводит значение переменной message на консоль, а функция sum() возвращает сумму двух чисел.

И, допустим, в коде TS мы хотим вызывать эти функции:

В этом случае подключение в файле globals.d.ts выглядело бы так:

Подключение объектов

Пусть в коде JavaScript есть следующий объект:

Используем этот объект в коде typescript:

В этом случае определение объекта в файле globals.d.ts выглядело бы так:

Подключени сложных объектов

Однако может возникнуть сложность с подключением более сложных объектов. Например, пусть есть такой объект javascript:

Для данного массива объектов в файле globals.d.ts мы можем определить соответствующий отдельному объекту интерфейс и подключить массив объектов некоторого интерфейса, который содержит два свойства X и Y:

И в TS мы сможем использовать этот массив:

Консольный вывод браузера:

Точка с координатами X = 10 Y = 34 Точка с координатами X = 24 Y = 65 Точка с координатами X = 89 Y = 12

Подключение классов

Рассмотрим последний пример - подключение в typescript классов, определенных в javascript. Пусть в коде JavaScript определен следующий класс Person:

Для этого класса в файле globals.d.ts определим следующее объявление класса:

Для класса прописываем все его поля и методы, при этом методы (в том числе конструктор) не имеют реализации, для них только определяются параметры и их типы и тип возвращаемого значения.

Начиная с ECMAScript 2015, в JavaScript появилась концепция модулей. TypeScript использует ту же концепцию.

Модули выполняются не в глобальной, а в своей собственной области видимости. Это означает, что переменные, функции, классы и т.д., объявленные в модуле, не видны вне модуля, за исключением тех случаев, когда они явно экспортированы с использованием одной из форм export . Также, чтобы использовать переменную, функцию, класс, интерфейс, и т.д., экспортированные из другого модуля, необходимо импортировать их с помощью одной из форм import .

Модули декларативны, и отношения между модулями определяются в терминах импорта и экспорта на файловом уровне.

Модули импортируют друг друга, используя загрузчик модулей, который во время выполнения кода находит и выполняет все зависимости модуля перед его выполнением. В JavaScript широко используются такие загрузчики, как CommonJS для Node.js и require.js для веб-приложений.

В TypeScript, как и в ECMAScript 2015, любой файл, содержащий import или export верхнего уровня, считается модулем.

Экспорт объявления

Любое объявление (переменой, функции, класса, псевдонима типа или интерфейса) может быть экспортировано с помощью добавления ключевого слова export .

Validation.ts
ZipCodeValidator.ts

Экспортное определение (Export statement)

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

Ре-экспорт

Модули часто расширяют другие модули. При этом они сами предоставляют доступ к части функций исходных модулей. Ре-экспорт не выполняет локального импорта и не создаёт локальную переменную.

ParseIntBasedZipCodeValidator.ts

При использовании модуля в качестве обёртки над одним или несколькими другими модулями, есть возможность ре-экспортировать сразу все их операторы экспорта с помощью конструкции export * from "module" .

AllValidators.ts

Импортировать практически так же просто, как и экспортировать. Импорт экспортированного объявления выполняется с помощью одной из форм import , приведённых ниже:

Импорт одного экспортированного элемента

импортируемый элемент также может быть переименован

Импорт всего модуля в одну переменную, и её использование для доступа к экспортированным элементам модуля

Импорт модуля ради «побочных эффектов»

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

Каждый модуль может содержать экспорт по умолчанию. Экспорт по умолчанию выделяется ключевым словом default , и в модуле может быть только одна такая инструкция. Для импорта экспорта по умолчанию используется отдельная форма оператора import .

Экспорт по умолчанию может оказаться очень полезным. Например, такая библиотека, как Jquery, может по умолчанию экспортировать jQuery или $ , что мы, вероятно, также импортируем под именем $ или jQuery .

JQuery.d.ts
App.ts

Классы и определения функций могут быть сразу обозначены в качестве экспортируемых по умолчанию. Такие классы и функции могут быть объявлены без указания имён.

ZipCodeValidator.ts
Test.ts
StaticZipCodeValidator.ts
Test.ts

Экспортируемым по умолчанию элементом можно быть обычное значение:

OneTwoThree.ts
Log.ts

У CommonJS и AMD существует концепция объекта exports , который содержит весь экспорт модуля.

Они также поддерживают замену объекта exports единичным пользовательским объектом. Экспорт по умолчанию призван заменить этот функционал. Оба подхода, однако, несовместимы. TypeScript поддерживает конструкцию export = , которую можно использовать для моделирования привычной схемы работы CommonJS и AMD.

Конструкция export = определяет единичный объект, экспортируемый из модуля. Это может быть класс, интерфейс, пространство имён, функция или перечисление.

Для импорта модуля, экспортированного с помощью export = , должна быть использована специфичная для TypeScript конструкция import let = require("module") .

ZipCodeValidator.ts
Test.ts

В зависимости от цели модуля, указанной во время компиляции, компилятор сгенерирует соответствующий код для Node.js (CommonJS), require.js (AMD), (UMD), SystemJS или собственных модулей ECMAScript 2015 (ES6). Для получения более подробной информации по поводу того, что делают вызовы define , require и register в сгенерированном коде, смотрите документацию по каждому отдельному модулю.

В этом простом примере показано, как имена, используемые во время импорта и экспорта, транслируются в код загрузки модуля.

SimpleModule.ts
AMD / RequireJS SimpleModule.js
CommonJS / Node SimpleModule.js
UMD SimpleModule.js
Система SimpleModule.js
Собственные модули ECMAScript 2015 SimpleModule.js

Ниже мы упростили реализацию валидатора из предыдущего примера, сведя его к экспорту единичного именованного экспорта из каждого модуля.

Для успешной компиляции необходимо указать цель модуля в командной строке. Для Node.js, используется --module commonjs ; для require.js — --module amd . Например:

В результате компиляции каждый модуль становится отдельным .js -файлом. Так же как и со ссылочными тегами, компилятор по операторам import найдёт и скомпилирует зависимые файлы.

Validation.ts
LettersOnlyValidator.ts
ZipCodeValidator.ts
Test.ts

В некоторых случаях может потребоваться загрузить модуль только при определённых условиях. В TypeScript возможно использовать приведённый ниже пример, чтобы применить данную или иную продвинутую технику загрузки модулей. Этот приём может использоваться для непосредственного вызова загрузчиков модулей без потери типобезопасности.

Компилятор для каждого модуля определяет, используется ли он в генерируемом JavaScript. Если идентификатор модуля есть только в описаниях типа и никогда в выражениях, тогда для этого модуля не будет сгенерирован вызов require . Такое пропускание неиспользуемых ссылок улучшает производительность, а также позволяет организовать опциональную загрузку модулей.

Основная идея примера заключается в том, что команда import > даёт доступ к типам, раскрываемым данным модулем. Как показано в блоке if ниже, загрузчик модуля вызывается динамически (с помощью require ). Таким образом применяется оптимизация пропуска неиспользуемых ссылок, что приводит к загрузке модуля только тогда, когда он нужен. Чтобы данный приём сработал, необходимо, чтобы идентификатор, определённый с помощью import , использовался только в описании типа (т.е. никогда в таком месте кода, которое попадёт в итоговый JavaScript).

Для поддержки типобезопасности используется ключевое слово typeof . Ключевое слово typeof , при использовании его в описании типа, создаёт тип значения (тип модуля в данном случае).

Динамическая загрузка модулей в Node.js
Пример: динамическая загрузка модулей в require.js
Пример: Динамическая загрузка модулей в System.js

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

Мы называем объявления, которые не определяют реализации, "внешними" (ambient). Обычно они задаются в файлах .d.ts . Если вы знакомы с C/C++, можете воспринимать их как заголовочные файлы .h . Давайте посмотрим на несколько примеров.

Внешние модули

В Node.js, большинство задач выполняется с помощью загрузки одного или нескольких модулей. Мы могли бы определить каждый модуль в его собственном файле .d.ts в объявлениями экспорта верхнего уровня, но гораздо удобнее поместить определения всех модулей в одном общем файле .d.ts . Чтобы это сделать, используйте конструкцию, похожую на внешние пространства имён. В ней используется ключевое слово module и заключенное в кавычки имя модуля, которое будет доступно для дальнейшего импорта. Например:

node.d.ts (упрощенный отрывок)

Теперь мы можем указать /// <reference> node.d.ts и загрузить модули с помощью import url = require("url"); .

Сокращенная запись объявления внешних модулей

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

declarations.d.ts

Все импортируемые элементы такого модуля будут иметь тип any .

Объявления модулей с использованием знаков подстановки

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

Теперь можно импортировать элементы, совпадающие с "*!text" или "json!*" .

Модули UMD

Некоторые библиотеки созданы таким образом, чтобы использоваться со многими загрузчиками модулей или без загрузчиков вообще (глобальные переменные). Их называют UMD или изоморфными (Isomorphic) модулями. Такие библиотеки можно подключить и с помощью импорта, и как глобальную переменную. Например:

math-lib.d.ts

Эту библиотеку можно подключить внутри модуля с помощью импорта:

Также эту библиотеку можно подключить как глобальную переменную, но это возможно сделать только внутри скрипта. (Скрипт — это файл без команд импорта и экспорта.)

Экспортируйте настолько близко к верхнему уровню, насколько это возможно

Чем меньше будет у пользователей модуля проблем с использованием экспортированных элементов, тем лучше. Добавление уровней вложенности делает модуль более громоздким, поэтому необходимо тщательно обдумывать его структуру.

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

Статические методы экспортируемых классов вызывают сходные проблемы, так как класс сам по себе добавляет уровень вложенности. Допустимо пойти на это в том случае, если вы точно знаете, что делаете, и введение дополнительного уровня вложенности добавит выразительности и ясно отразит назначение модуля. В противном случае рекомендуется использовать вспомогательные функции (helper function).

Если вы экспортируете только один class или одну function , используйте export default

Аналогично "экспорту максимально близко к верхнему уровню", использование экспорта по умолчанию (default export) облегчает жизнь пользователям вашего модуля. Если основной задачей модуля является размещение и экспортирование одного специфического элемента, то необходимо всерьез рассмотреть использование экспорта по умолчанию. Такой подход делает и саму процедуру импорта, и использование импортированных элементов немного проще. Например:

MyClass.ts

MyFunc.ts

Consumer.ts

Такой подход оптимален для пользователей модуля. Они могут дать вашему типу наиболее удобное для них наименование ( t в данном случае) и будут избавлены от лишнего обращения «через точку» для поиска ваших объектов.

Если вы экспортируете несколько объектов, поместите их на верхний уровень

MyThings.ts

Соответственно при импорте:

Явно определяйте импортированные имена

Consumer.ts

Используйте шаблон импорта пространства имен в случае импорта большого количества элементов

MyLargeModule.ts

Consumer.ts

Ре-экспорт с целью расширения функционала

Зачастую бывает необходимо расширить функциональность модуля. В JavaScript наиболее распространён метод дополнения исходного объекта расширениями (extensions), аналогично тому, как работает JQuery. Как было упомянуто ранее, модули не сливаются подобно объектам глобальных пространств имён. Рекомендуется не изменять исходный объект, а экспортировать новый элемент, предоставляющий новую функциональность.

Давайте рассмотрим реализацию простого калькулятора, созданную в виде модуля Calculator.ts . Из модуля также экспортируется вспомогательная функция, предназначенная для тестирования функциональности калькулятора путём передачи списка входных строк и записи результата.

Calculator.ts

Новый модуль ProgrammerCalculator экспортирует такой же API, что и исходный модуль Calculator , но при этом не изменяет в нём ни одного объекта. Ниже приведён тест класса 'ProgrammerCalculator':

TestProgrammerCalculator.ts

import < Calculator, test >from "./ProgrammerCalculator"; let c = new Calculator(2); test(c, "001+010 -13">Не используйте в модулях пространства имён

Когда программисты только начинают использовать организацию кода с помощью модулей, они часто размещают экспортируемые элементы в пространствах имён, создавая таким образом дополнительные уровни вложенности. Но у модулей есть своя собственная область видимости, и извне видны только экспортированные элементы. Поэтому пространства имён не способны принести ощутимую пользу при работе с модулями.

Пространства имён являются важным инструментом для предотвращения конфликтов имён. Например, у вас могут быть My.Application.Customer.AddForm и My.Application.Order.AddForm — два типа с один именем, но разными пространствами имен. А с модулями такой проблемы не будет. Нет серьёзных оснований для создания двух объектов с одинаковым именем внутри модуля. С точки зрения пользователя, он может выбрать любое имя для импортируемого модуля, поэтому случайные конфликты имен невозможны.

Более подробная информация о пространствах имен и модулях Namespaces and Modules.

Индикаторы опасности

Ниже приведен список тревожных признаков, касающихся структурирования модулей. Лишний раз убедитесь, что вы не пытаетесь создавать пространства имен для ваших внешних модулей, если любое из следующих утверждений относится к вашей ситуации:

вОт JavaScript к серии TypeScript》 В этой статье мы изучили знания, связанные с TypeScript. В основе TypeScript лежат статические типы.Мы определяем многие типы при написании TS, но основные библиотеки написаны на JavaScript и не поддерживают системы типов. Так как же сделать эти сторонние библиотеки доступными для вывода типов?

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

Файл определения типа

В TypeScript мы можем легко определять типы при написании кода:

Но все основные библиотеки написаны на JavaScript. TypeScript, как надмножество JavaScript, естественно, должен учитывать, как библиотеки JS могут также определять статические типы.

После серии исследований TypeScript предложилtsd(Устарело),typings(Устарело), ​​наконец, реорганизовал определение типа в TypeScript 2.0 и предложилDefinitelyTyped。

DefinitelyTyped Позволяет опубликовать "файл определения типа (* .d.ts)" в npm В редакторе (или плагине) статический тип в библиотеке JS может быть обнаружен.

Файл определения типа .d.ts В конце концов, он в основном используется для определения типа.

Например этофайл определения типа jQuery Фрагмент кода (внесены некоторые изменения для облегчения понимания)

Определение типа

*.d.ts Писать очень просто.После крещения хорошей системы статических типов TypeScript стоимость изучения грамматики становится очень низкой.

Мы можем использовать type Используется для определения переменных типа:

можно увидеть type Фактически, можно определять различные типы форматов, а также их можно комбинировать с другими типами.

Конечно, мы также можем использовать interface Определите наш сложный тип, в TS мы также можем напрямую определить interface :

interface с type (Или class ) Очень похожий.

Но type Смысл в том, чтобы определить собственный тип. Когда базовые типы, предоставляемые TS, не удовлетворяют, вы можете использовать type Свободно комбинируйте свои новые типы и interface Это должен быть внешний выходной интерфейс.

type Не может быть унаследовано, но interface Можно:

declare

declare Может создать *.d.ts Для переменных в файле declare может быть только самой внешней областью:

По сути, необходимо использовать определения верхнего уровня declare , class Также:

namespace

Чтобы предотвратить дублирование типов, используйте namespace Используется для разделения региональных блоков, разделения повторяющихся типов, верхнего уровня namespace Необходимость declare Экспорт во внешнюю среду, подпространство имен не требуется declare 。

Определение комбинации

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

Динамические свойства

Некоторые типы имен атрибутов являются динамическими и неизвестными, например:

Мы можем использовать имена динамических атрибутов для определения типов:

Обход типов

Когда вы знаете определенный диапазон типов, вы можете использовать in с keyof Для обхода типов, таких как пример ChinaMobile выше, мы можем использовать in Имя атрибута должно быть одним из трех операторов:

Мы также можем использовать keyof для согласования параметров метода

Интегрированный выпуск

Есть два основных способа опубликовать файлы определения типа в npm :

В первом случае файл определения типа будет автоматически обнаружен и распознан после установки пакета. Последний необходимо установить через npm i @ types / xxxx, о чем мы говорили ранее.DefinitelyTyped , Используется для расширения объявления типа библиотеки JS.

Встроенный файл определения типа

Встроенное определение типа предназначено для публикации вашего файла определения типа и пакета npm вместе. Вообще говоря, файлы определения типа помещаются в корневой каталог пакета. types В каталоге, напримерvue:

Если в твоей сумке есть хозяин .js Файл, должен быть в package.json Укажите файл определения основного типа.

Настроить types Или typeings Атрибут указывает на файл определения связанного типа. Например, каталог пакета выглядит следующим образом:

Если имя файла определения основного типа - index.d.ts и он находится в корневом каталоге пакета, указывать его с помощью атрибута types не нужно.

Если вы отправите посылку, package.json Используется в files Полевые слова ( npm Будет основано на files Настроенные правила определяют, какие файлы публиковать), вам необходимо вручную добавить файл определения типа:

Если вы отправляете только вторичный каталог, поместите файл определения типа в соответствующий вторичный каталог:

Опубликовать в @types organizationatio

Опубликовать в @types organizatio Пакет означает, что исходный пакет не содержит файла определения типа. После того, как третья сторона / или первоначальный автор определят файл определения типа, опубликуйте его в@types в. Например@types/express。

Согласно с DefinitelyTyped Правила и редакторы (и плагины) автоматически определяют статические типы.

@types Следующий пакет отDefinitelyTyped Выпущено автоматическиtypes-publisher орудие труда.

Подарки из роз, рука оставила стойкий аромат.

Опубликовать в @types organizatio Пакет можно передатьTypeSearch Поиск и извлечение, использование npm install --save-dev @types/xxxx установка:


Интеллектуальная рекомендация

совместный запрос mysql с тремя таблицами (таблица сотрудников, таблица отделов, таблица зарплат)

1. Краткое изложение проблемы: (внизу есть инструкция по созданию таблицы, копирование можно непосредственно практиковать с помощью (mysql)) Найдите отделы, в которых есть хотя бы один сотрудник. Отоб.


[Загрузчик классов обучения JVM] Третий день пользовательского контента, связанного с загрузчиком классов


IP, сеанс и cookie

Читайте также: