Практическое руководство по использованию TypeScript для разработчиков JavaScript.

В этой серии статей предполагается, что читатель имеет разумное понимание JavaScript ES2015 (Learn ES2015) и минимальное понимание TypeScript (TypeScript за 5 минут).

Если вы заинтересованы в том, чтобы продолжить, мы бы порекомендовали вам сформировать проект, используя упрощенную настройку в разделе Backend статьи Tech Stack 2019: Core и используйте Visual Studio Code с расширением TSLint в качестве редактора.

Есть две крайние точки зрения на переход от JavaScript к TypeScript.

Сначала "что это, черт возьми?"

Другой - «в чем дело?»



Более точная перспектива - это зависит от сделанного выбора.

Первый пример взят из Ts.ED (TypeScript Framework поверх Express), в котором используются декораторы:

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

- TypeScript - Декораторы

С другой стороны, можно писать приложения TypeScript Express, которые практически не отличаются от своих эквивалентов на JavaScript; например, нам нужно изменить только одну строку (import против require) в Express Hello World Example .

В то же время, даже если кто-то выберет более традиционный подход JavaScript (наш подход в этой статье и мои общие предпочтения), есть несколько важных TypeScript концепции, не описанные в TypeScript за 5 минут, которые необходимо знать.

примечание: в качестве примечания: официальный TypeScript Handbook написан очень хорошо (множество примеров и т. д.); в то же время трудно отличить часто встречающиеся концепции от более тонких крайних случаев.

Вывод типа

В TypeScript есть несколько мест, где вывод типа используется для предоставления информации о типе, когда нет явной аннотации типа.

- TypeScript - Вывод типа

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

...
const port = 3000;
...

примечание: в этих примерах я снова вставляю точки с запятой; мне все еще кажется странным без них.

В этом случае компилятор TypeScript может сделать вывод, что порт - это номер, поскольку он назначен номеру ( 3000).

Можно было явно (но с избыточностью) ввести порт с помощью:

...
const port: number = 3000;
...

С другой стороны, необходимо явно указать переменные, когда они объявлены без присваивания:

...
let port: number;
port = 3000;
...

Другой пример вывода типа (контекстная типизация) скрыт в строке ниже:

...
app.get('/', (req, res) => res.send('Hello World!'))
...

В нашем редакторе мы видим, что res типа Response:

В этом случае компилятор TypeScript может вывести базу сигнатуры типа функции на основе своего контекста, в данном случае в качестве второго параметра функции get.

С другой стороны, мы должны явно ввести параметры функции, когда они объявлены вне контекста:

import express, { Request, Response } from 'express';
...
const handleGet = (req: Request, res: Response) => res.send('Hello World');
app.get('/', handleGet);
...

Файлы декларации

Предыдущий пример освещает одну из самых больших проблем с использованием TypeScript; отсутствие документации по типам для сторонних библиотек. Хотя это очевидно, если взглянуть на это, как мы узнали, что нужно импортировать типы Request и Response из express?

Официальная ссылка Express на Response не упоминает типы TypeScript. Фактически, библиотека Express не предоставляет собственные определения типов, а скорее зависит от библиотеки @ types / express (экспортированной из ОпределенноTyped ).

Важно отметить, что сторонние библиотеки, например, Express, поставляются как JavaScript; , поэтому нам нужно потреблять файлы объявления типа, чтобы использовать их с TypeScript. Эти файлы объявления типа могут поставляться в том же пакете, что и JavaScript, или в отдельном пакете (как в случае Express).

Давайте рассмотрим типичный сценарий использования сторонней библиотеки (скажем, в новом проекте TypeScript); в данном случае Express.

Начнем с установки библиотеки в соответствии с ее документацией, например, в Express документации :

npm install express

Мы используем их документацию для использования библиотеки (пример привет мир; замена require на import) и сразу получаем ошибку компилятора TypeScript:

К счастью, ошибка подсказывает нам решение:

npm install @types/express

После установки этой дополнительной библиотеки ошибки устранены.

Хотя пример Express hello world построен так, что можно вывести все типы, в конечном итоге, вероятно, захочется использовать явную типизацию, например,

...
const handleGet = (req: Request, res: Response) => res.send('Hello World');
...

Один из приемов определения набора текста (скажем, типа Response) заключается в том, чтобы наблюдать за предполагаемым набором текста (при наведении курсора на параметры в редакторе) в исходном коде и угадывать типы, которые необходимо импортировать (9 раз из 10 это работает для меня).

Однако в зависимости от того, над чем навести курсор мыши, можно прийти к другому решению. Например, при наведении курсора на метод get мы видим, что второй параметр get - это RequestHandler (или их массив); с использованием параметров отдыха.

Используя RequestHandler, мы получаем более явное (и, следовательно, лучшее) определение handleGet.

import express, { RequestHandler } from 'express';
...
const handleGet: RequestHandler = (req, res) => res.send('Hello World');
app.get('/', handleGet);
...

примечание: признание… До написания этой статьи я привык использовать менее явную реализацию с использованием интерфейсов Request и Response.

Более удовлетворительный ответ (вместо предположения об импорте) состоит в том, что можно проверить файл определения типа; ./node_modules/@types/express/index.d.ts. Затем мы видим, что он экспортирует RequestHandler.

...
interface RequestHandler extends core.RequestHandler { }
...

который расширяет RequestHandler, экспортированный в ./node_modules/@types/express-serve-static-core/index.d.ts.

...
export interface RequestHandler {
    ...
    (req: Request, res: Response, next: NextFunction): any;
}
...

Дальнейшие действия

Мы продолжим изучение часто используемых, но менее очевидных концепций TypeScript в TypeScript: The Hard (er) Parts: Part 2.