Руководство из четырех частей для опытных разработчиков JavaScript

TypeScript — это язык программирования, разработанный и поддерживаемый Microsoft. Это строгий синтаксический надмножество JavaScript, добавляющий к языку необязательную статическую типизацию. Он предназначен для разработки больших приложений и транспилируется в JavaScript.

В этой статье мы даем краткое введение в язык, отсылая читателей к официальной документации для дальнейшего чтения. Ожидается знание современного Javascript (ES2015+), а также можно узнать больше о JavaScript в сети разработчиков Mozilla.

Начиная с TypeScript

Поскольку TypeScript (TS) является расширенным набором JavaScript (JS), вы можете начать с минимального использования TS в своем коде или вообще без него и постепенно переходить к большему количеству его функций. Вам нужна среда разработки, которая преобразует TS в JS, и WebSStorm от JetBrains — моя личная рекомендация, но есть много других хороших редакторов, которые вы можете использовать.

По своей сути TypeScript позволяет добавлять в код типы, что позволяет компилятору TypeScript статическипроверить ввод во время компиляции. Под этим мы подразумеваем, что TypeScript проверяет ваш код на наличие ошибок типа во время компиляции, а не во время выполнения (именно там выполняются динамические проверки).

Аннотирование вашего кода типами позволяет компилятору отслеживать поток значений в программе и проверять, что функции и другие программные конструкции получают и возвращают значения типов, аннотированных им программистом (или выведенных компилятором). Удивительное количество ошибок выявляется с помощью проверки типов, и, как бывший неверующий, я теперь всем сердцем поддерживаю статическую проверку типов в JavaScript и код исключительно на TypeScript.

Добавление типов в JavaScript — часть 1

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

Примитивная типизация

Примитивные типы в TypeScript — это string, number и boolean, и их можно аннотировать к переменным следующим образом.

const text: string;
const amount: number;
const loggedIn: boolean;

Вывод типа

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

const text = "Hello, World!";
const amount = 1000;
const loggedIn = False;

Обычно достаточно способный редактор, такой как WebStorm, предоставляет множество подсказок по вводу (как правило, путем использования TSLint), которые помогут вам определить, когда добавлять явные типы или полагаться на типы, выведенные компилятором. Например, если у вас есть переменная, которая может быть либо строкой, либо массивом строк, вам, вероятно, не нужен следующий вывод типа:

const text = "A" // TypeScript infers text is of type string

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

const text: string | Array<string> = "A"

Типы массивов и объединений

Выше мы ввели два новых понятия. Для типов массивов используется формат Array<type>, где type представляет тип элементов массива (строка в приведенном выше примере). Во-вторых, типы объединений создаются с помощью |. Другой пример:

const primitive: string | number | boolean;

В приведенном выше примере переменная primitive может быть строкой, числом или логическим значением. Теперь важный момент: при использовании типов объединения любая операция должна быть допустима для каждого типа в этом объединении. Например, ниже будет ошибка типа, потому что числа и логические значения не имеют метода toUpperCase:

console.log(primitive.toUpperCase());      // <-- Type Error

Чтобы обойти это, вам нужно будет сделать что-то вроде:

if (typeof primitive === "string") {
  console.log(primitive.toUpperCase());
}

Этот пример является небольшой иллюстрацией того, как проверка типов предотвращает ошибки в коде, поскольку она предотвращает некоторые незаконные операции во время выполнения — без приведенной выше защиты типов JavaScript выдавал бы ошибку во время выполнения. если primitive сохранил номер, и мы попытались позвонить по нему toUpperCase.

ЛЮБОЙ тип

В завершение этого раздела отметим, что TypeScript имеет тип any, который эффективно позволяет обойти все проверки типов. Обычно не рекомендуется использовать тип any, но в некоторых случаях вам может понадобиться (но старайтесь избегать этого!).

let obj: any = { x: 0 };
// None of the following lines of code will throw compiler errors.
// Using `any` disables all further type checking, and it is assumed
// you know the environment better than TypeScript.
obj.foo();
obj();
obj.bar = 100;
obj = "hello";
const n: number = obj;

Добавление типов в JavaScript — часть 2

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

Добавление типов к функциям

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

function add(x: number, y: number, message: string):number {
  console.log(message);
  return x + y;
}

Создание пользовательских типов

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

type Point {
  x: number;
  y: number;
}
interface Point {
  x: number;
  y: number;
}

Таким образом, мы можем добавлять типы к объектам следующим образом:

const point: Point
// Equivalent to the below anonymous object type:
const point: { x: number, y: number }

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

type leftAlignment = "left";   // Only permitted value is "left"
type alignment = leftAlignment | "right" | "center"
type validNum = -1 | 0 | 1
type validInput = Point | validNum | 5    // Refer 'Point' def above

Добавление типов к классам

Приведенные выше концепции естественным образом распространяются на классы.

class PointAdder {
  x: number;
  y: number;
  
  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
  adder(a: number): number {
    return this.x + this.y + a;
  }
}

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

const test: PointAdder;

Следующие шаги

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