TypeScript: основы

Что такое TypeScript?

TypeScript — один из языков программирования, получивший широкое признание в профессиональных кругах. Многие веб-разработчики отдают ему предпочтение и используют для создания новых программ. Краткий ответ на вопрос “Что такое TypeScript?” заложен в его названии: TypeScript — это язык программирования, реализовавший систему типов JavaScript. Иными словами, TypeScript — язык расширения возможностей JavaScript.

Почему мы используем TypeScript?

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

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

Предотвращение ошибок

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

Давайте сравним два кода ниже и посмотрим, как TypeScript заранее предотвращает ошибки.

// JavaScript
function add(num1, num2) {
 return num1 + num2;
}
// TypeScript
function add(num1: number, num2: number): number {
 return num1 + num2;
}

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

Результат JavaScript

Добавим числа 10 и 20 с помощью функции add (). Ожидаемый результат, который мы должны получить, — 30.

Однако, если строковое значение будет введено в функцию add (), написанную с помощью JavaScript, мы не сможем получить ожидаемое значение с помощью функции add ().

Неверный результат JavaScript

Посмотрим теперь на код, написанный на TypeScript. Как видите, редактор кода Visual Studio Code уже предупреждает нас о том, что в аргумент функции вставлено неверное значение.

Ошибка TypeScript

Автозаполнение кода и руководство

Еще одно преимущество TypeScript заключается в том, что он позволяет нам максимально использовать возможности инструмента разработки при написании кода. Visual Studio Code, который обычно используется в разработке клиентской части приложений, оптимизирован для работы в TypeScript, поскольку этот инструмент создан на основе TypeScript.

Давайте посмотрим на код JavaScript ниже и оценим преимущества добавления типа в JavaScript для разработчика.

// JavaScript
function add(num1, num2) {
 return num1 + num2;
}

let total = add(10, 20);
total.toLocaleString();

Приведенный выше код использует функцию add (), ранее выведенную нами, чтобы получить результат как сумму двух чисел, а затем добавляет “toLocaleString() API”, где числа помечены в соответствии с выражением определенного языка. Не имеет значения, какую роль выполняет API под названием “toLocaleString ()”, но важно, что JavaScript не мог распознать во время написания кода, что тип общей переменной — число.

Другими словами, сами разработчики ожидают результата функции add (), а затем предполагают, что типом результата должно быть число, прежде чем писать код “toLocaleString ()”, чей API содержит число. Взгляните на этот процесс.

Как вы видели, тип общей переменной произвольный, поэтому я вводил данные поочередно, чтобы написать “toLocaleString ()”, чей API предоставляет JavaScript Number. Если бы я допустил опечатку и написал “toLocalString()”, заметить ошибку можно было бы только тогда, когда файл ex-1.js был бы запущен в браузере.

А что произойдет, если код будет написан в TypeScript, как показано ниже?

// TypeScript
function add(num1: number, num2: number): number {
 return num1 + num2;
}

let total = add(10, 20);
total.toLocaleString();

Поскольку тип уже указан для общей переменной, Visual Studio Code может предварительно просматривать API для этого типа, поэтому позволяет быстро и точно записать API с помощью вкладок, а не вводить данные поочередно.

Типы

Number

const num: number = -6;

String

const str: string = 'hello';

Boolean

const boal: boolean = false;

Undefined и Null

Типы Undefined и Null редко бывают необходимы сами по себе, однако становятся полезными при использовании с типом Union.

type Person: string | undefined | null;

Unknown и Any

Лучше не допускать использования типов Unknown и Any в TypeScript, чтобы избежать создания кода, характерного для JavaScript.

// unknown
let notSure: unknown = 0;
notSure = 'he';
notSure = true;

// any
let anything: any = 0;
anything = 'hello';

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

Void

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

// Объявленный void
function print(): void {
console.log('hello');
}
// Опущенный void
function print() {
 console.log('hello');
}

Never

Этот тип обычно используется для функции исключения или функции, имеющей бесконечный цикл.

// Функция исключения
function throwErr(message: string): never {
 // ... code
 throw new Error(message);
}

// Бесконечный цикл в функции
function infinite(in: number): never {
 // ... code
 while(true){}
}

Object

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

let obj: object;

function acceptSomeObject(obj: object) {}

acceptSomeObject({ name: 'aiden' });
acceptSomeObject({ animal: 'dog' });

Array

const scores: number[] = [1, 2, 3];

// Использование дженерика

const scores: Array<number> = [1, 2, 3];

Tuple

Tuple представляет собой массив с элементами разных типов. Не стоит его использовать опрометчиво, кроме как для написания интерфейсов, псевдонимных типов или классов, потому что они менее разборчивы для чтения. Однако Tuple может быть полезен, если что-то возвращается в динамичном режиме, есть неоднозначный запрос в классе или интерфейсе, и пользователь определяет и записывает имя, группируя другие типы динамически связанных данных. Tulpe часто используется в React-хуках.

let student: [string, number];
student = ['name', 123];
student[0]; // name
student[1]; // 123

const [name, age] = student;

Alias

Если необходимо определить ваш собственный тип, вы можете использовать тип Alias.

type Text = string;

const name: Text = 'aiden';
const address: Text = 'canada';

type Num = number;

Можно определить примитивные типы, а также типы форм объектов.

type Student = {
 name: string;
 age: number;
};

const student: Student = {
 name: 'aiden',
 age: 12,
};

Важный момент заключается в том, что нельзя назначить что-либо другое, если это не включено в объект, который уже был объявлен. При наличии других данных, это будет ошибкой.

// Произошла ошибка
const student: Student = {
 animal: 'dog',
 age: 12,
};

Union

Это тип, который означает A или B подобно OR-оператору “||” в JavaScript. Таким образом, тип Union лучше использовать в случае, когда нужно определить место только для одного из всех возможных случаев.

type Direction = 'left' | 'right' | 'up' | 'down';

function move(direction: Direction) {
 console.log(direction);
}

move('down')

Функция move (), реализованная выше, может принимать в качестве факторов только аргументы, объявленные в типе Direction.

type SuccessState = {
 response: {
  body: string;
 };
};

type FailState = {
 reason: string;
};

type LoginState = SuccessState | FailState;

function printLoginState(state: LoginState) {
 if ('response' in state) {
  console.log(state.response.body);
 } else {
  console.log(state.reason);
 }
}

Приведенный выше код не вызывает ошибок, но рекомендуется использовать тип Discriminated Union, описанный ниже.

Discriminated Union

Тип Discriminated Union означает присвоение общего ключа, предназначенного для совместного использования внутри типа Union.

type SuccessState = {
 result: 'succes';
 response: {
  body: string;
 };
};

type FailState = {
 result: 'fail';
 reason: string;
};

type LoginState = SuccessState | FailState;

function printLoginState(state: LoginState) {
 if (state.result === 'success') {
   console.log(state.response.body);
 } else {
   console.log(state.reason);
 }
}

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

Intersection

Если в типе Union реализуется концепция “OR” (“ИЛИ”), то в типе Intersection — концепция “AND” (“И”).

type Student = {
 name: string;
 score: number;
};

type Worker = {
 empolyeeId: number; 
 work: () => void;
};

function internWork(person: Student & Worker) {
 console.log(person.name, person.empolyeeId, person.work());
}

internWork({
 name: 'aiden',
 score: 1,
 empolyeeId: 123,
 work: () => {},
});

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

Enum

Это тип, который собирает и управляет значениями различных соотносимых констант в одном месте. Другими словами, тип Enum используется для набора конкретных значений.

В JavaScript константы обычно объявляются следующим образом.

// Константы в JavaScript
const MAX_NUM = 6;
const MAX_STUDENTS_PER_CLASS = 10;
const MONDAY = 0;
const TUESDAY = 1;
const WEDNESDAY = 2;

В JavaScript API под названием freeze() может использоваться для придания объектам вида Enum, чтобы константы можно было сгруппировать и определить только один раз во избежание изменений.

// Создание Enum в JavaScript
const DAYS_ENUM = Object.freeze({ MONDAY: 0, 
                                  TUESDAY: 1, 
                                  WEDNESDAY: 2 });
const dayOfToday = DAYS_ENUM.MONDAY;

Однако в TypeScript при объявлении Enum заглавными буквами пишется только первая буква, а не полностью все имя переменной.

enum Days {
 Monday,
 Tuesday,
 Wednesday,
 Thursday,
 Friday,
 Saturday,
 Sunday,
}

console.log(Days.Monday); // 0

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

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

let day: Days = Days.Saturday;
day = Days.Tuesday; // Okay
day = 10; // Oops

console.log(day); // 10

По этой причине в TypeScript тип Union используется чаще, чем Enum. Однако, когда необходимо обмениваться данными с другими языками, например, если веб-приложению и мобильному приложению необходимо взаимодействовать друг с другом, тип Union не может быть распознан на других языках, поэтому приходится использовать тип Enum.

Inference

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

TypeScript проверяет данные, присвоенные переменной, и считает текст переменной типом String, если он не объявляет String, как показано в приведенном ниже коде.

// Тип Inference в TypeScript
let text = 'hello';
let text: string = 'hello';

function add(x: number, y: number) {
 return x + y;
}

function add(x: number, y: number): number {
 return x + y;
}

const result = add(1, 3);
console.log(result);

Хотя при реализации простых функций удобно использовать Inference, его использование при создании сложных функций может затруднить понимание кода разработчиками. Поэтому рекомендуется взять за правило всегда объявлять тип возврата при реализации функции.

Assertion

TypeScript позволяет переопределять Inference любым удобным для вас способом. Тип Assertion обычно используется для переноса кода из JavaScript, что рекомендуется, когда вы точно знаете тип возвращаемой функции или тип переменной. Если тип прогнозирования неопределен и вы его используете, ошибок во время компиляции и при написании кода не будет, но вы увидите неожиданные результаты в веб-браузере.

function jsStrFunc(): any {
 return 2;
}

const result = jsStrFunc();
console.log((result as string).length);
console.log((<string>result).length); // тот же результат выше 

const wrong: any =5;
console.log((wrong as Array<number>).push(1)); // Это ужасно

Обучение

Посмотрите это видео и поучитесь реализовать простую функцию calculate() с использованием вышеперечисленных типов.


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

Читайте нас в TelegramVK и Яндекс.Дзен


Перевод статьи Aiden Kim: TypeScript. What is TypeScript?

Предыдущая статьяПишем асинхронный неблокирующий Rest API на Java