Знакомство с TypeScript

28-10-2019

Введение

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

Установка и предварительные настройки

Для установки воспользутесь командой npm install typescript. После установки TypeScript компилятор будет доступен по команде tsc. Браузер или Node.js не понимают TypeScript, они работают только с javascript. Typescript код + TypeScript 'компиллятор' = обычный JavaScript Если Вы желаете попробовать TypeScript в своём браузере используйте песочницу . Большинство примеров из этой статьи могут быть напрямую вставлены в поле TypeScript этого сайта и Вы сможете быстро увидеть как TypeScript преобразуется в JavaScript. Для запуска TypeScript кода в Node.js Вам понадобиться библиотека ts-node, установить которую Вы сможете с помощью команды:

npm install -g typescript ts-node .

Примечание: для запуска в Linux/MacOs Вам нужно будет использовать sudo перед указанной командой.

Для написания и запуска TypeScript кода установите Visual Studio Code. Для проверки работоспособности TypeScript кода создайте в Visual Studio Code файл index.ts с начинкой:

const  hello  =  "Hello"
const  world  =  "World"
console.log(hello  +  "  "  +  world)

Напишите tsc index.ts в окне терминала и вы должны будете увидеть созданный файл index.js , содержащий код:

var  hello  =  "Hello"
var  world  =  "World"
console.log(hello  +  "  "  +  world)

Для запуска index.js файла введите в терминале команду node index.js :

$ node index.js
Hello World

Мы убедились в том, что ts (TypeScript) настроен у нас правильно. Теперь для удобства разработки, вместо этих команд (tsc index.ts и node index.js) будем набирать одну: ts-node index.ts, которая сделает тоже самое.

Типы

Typescript является языком со статической типизацией. Тип не может быть изменен в ходе выполнения программы. Это позволяет снизить большое количество ошибок и выявить многие из них еще на этапе компиляции. Все типы в TypeScript являются подтипами главного типа, которым является тип Any. Данный тип обозначается ключевым словом any. Тип Any — единственный, который может представлять любое значение JavaScript без всяких ограничений. Все остальные типы накладывают определенные ограничения на свои значения. Примитивными типами являются Number, String,Boolean, Symbol, Void, Null, Undefined и также типы-перечисления (enums), определяемые пользователем.

Тип Any

Тип Any используется когда мы не знаем какой тип должна иметь переменная (например когда переменная получает данные из сторонней библиотеки).

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

let someVar: any = 444;  
someVar= "потом может стать другим типом, например строкой";  
someVar= false; // или boolean

Рекомендуется всегда явно указывать тип там, где это возможно во избежание ошибок. И не стоит везде использовать тип Any, т.к. в этом случае исчезают преимущества, которые дает TypeScript при использовании конкретных типов.

let withoutType; // переменная имеет тип Any

Тип Number

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

let a: number; // Явное указание типа  
let b = 0; // Тоже, что и b: number = 0  
let c = 1.5; // Тоже, что и c: number = 1.5
let decimal: number = 6;  
let hex: number = 0xf00d;  
let binary: number = 0b1010;  
let octal: number = 0o744;
let s = z.toFixed(2); // Свойство интерфейса Number

Тип Boolean

Наиболее базовым типом является логический истина (true) или ложь (false), который в Javascript и Typescript называется boolean. Все переменные этого типа реализуют также глобальный интерфейс Boolean.

let isDone: boolean = false;
let checked = true; // Тоже, что и let checked: boolean = true;

Тип String

Тип String соответствует аналогичному в JavaScript и представляет собой последовательность символов в кодировке Unicode UTF-16. Все переменные данного типа реализуют глобальный интерфейс String. Как и Javascript, в Typescript используются двойные (") или одинарные (') кавычки для обрамления текстовых данных.

let color: string = "blue"; 
color = 'red';
let empty = "";
str = color.charAt(1); // Свойство интерфейса 'String'

Вы также можете использовать строки с шаблонами, которые могут быть многострочными и иметь встроенные выражения. Эти строки окружаются обратными апострофами или кавычками(`) и встроенные выражения обозначаются как ${ выражение }.

let fullName: string = `Bob Bobbington`; 
let age: number = 37; 
let sentence: string = "Hello, my name is " + fullName + ".\n\n" + "I'll be " + (age + 1) + " years old.";
или
let sentence: string = `Hello, my name is ${ fullName }. I'll be ${ age + 1 } years old.`;

Тип Void

void это нечто противоположное any: отсутствие каких-либо типов. Чаще всего он используется в качестве возвращаемого типа функций, которые не возвращают никакого значения.

function warnUser(): void {
alert("This is my warning message");
}

Объявление переменных с типом void бесполезно, потому что вы можете присвоить им только значения undefined или null:

let unusable_undefined: void = undefined;
let unusable_null: void = null;

Тип Null and Undefined

Типы Null и Undefined соответствуют одноименным типам в JavaScript. Данные типы являются подтипами для всех остальных типов по умолчанию.

let u: undefined = undefined;// тоже самое, что и y: any = undefined 
let n: null = null;
let x = null; // тоже самое, что и x: any = null 
let n: number = null; // Примитивные типы могут быть null  
let m: number = undefined; // Примитивные типы могут быть undefined  
let e: Null; // Ошибка  
let r: Undefined; //Ошибка

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

Стоит отметить, что если использовать директиву компилятора --strictNullChecks, null иundefined могут быть присвоены только переменной типаvoid и переменным с типамиnull или undefined соответственно. Это помогает избежать множества ошибок. В таком случае, если переменной нужно присвоить значение с типом string илиnull илиundefined, можно использовать тип объединение string | null | undefined.

Тип Never

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

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

function error(message: string): never {
    throw new Error(message);
}

// Выведенным типом fail() будет never
function fail() {
    return error("Something failed");
}

// нет выхода из этой функции
function infiniteLoop(): never {
    while (true) {
    }
}

Тип Symbol

Тип Symbol является примитивным и соответствует одноименному типу в языке JavaScript. Данный тип предоставляет уникальные идентификаторы, которые могут быть использованы как ключи для свойств объекта.

Значения, имеющие тип Symbol реализуют глобальный объект ‘Symbol’, который имеет набор методов и свойств, которые могут быть вызваны как функции.

let secretKey = Symbol();   
let obj = {}; obj[secretKey] =secret message; // Символ как свойство  
obj[Symbol.toStringTag] =test;

Тип Array

TypeScript, как и JavaScript, имеет массивы значений. Тип массива может быть определен одним из двух способов. Первый - обозначать тип элементов массива перед []:

let list: number[] = [1, 2, 3];

Второй способ - использовать обобщение Array<elemType>:

let list: Array<number> = [1, 2, 3];

Созданная переменная также реализует обобщенный интерфейс Array< T > , где Т — тип элементов массива. Свойство length данного интерфейса возвращает количество элементов массива.

interface Array<T> {   
  length: number; // длина массива  
  [x: number]: T; // сигнатура для доступа к элементу массива по его индексу  
  // ... остальные методы  
}

Пример:

let list: Array<number> = [1, 2, 3];  
list[1] = 4; // [1, 4, 3]  
let length = list.length; // 3

Тип Tuple (кортеж)

Тип Tuple дает вам возможность объявить массив с известным фиксированным количеством элементов, которые не обязаны быть одного типа. Например, вы хотите иметь значение Tuple как пару "строка" и "число":

// Объявление типа tuple
let x: [string, number];
// Его инициализация
x = ['hello', 10];// OK
// Некорректная инициализация вызовет ошибку
x = [10,'hello'];// Error

Когда вы получаете элемент с известным идексом, будет возвращен тип этого элемента:

console.log(x[0].substr(1));// OK
console.log(x[1].substr(1));// Error, 'number' does not have 'substr'

При получении элемента с идексом вне известного диапазона, будет возвращен тип Union:

x[3] ='world';// OK, тип string может быть присвоен (string | number)
console.log(x[5].toString());// OK, 'string' и 'number' оба имеют метод toString
x[6] =`true`;// Ошибка, boolean это не (string | number)

Можно создавать именованные кортежи путем объявления интерфейса, унаследованного от Array< T > и введя численно именованные свойства.

interface KeyValuePair<K, V> extends Array<K | V> { 0: K; 1: V; } 
let x: KeyValuePair<number, string> = [10,ten”];

Тип Enum (Перечисления)

Полезным дополнением к стандартному набору типов из Javascript является тип Enum - это более удобный способ задания понятных имен набору численных значений.

enum Color {Red, Green, Blue};
let c: Color = Color.Green;

По умолчанию перечисления (Enum) начинаются с 0. Вы можете изменить это путем прямого указания значения для одного из членов перечисления. Например, мы можем начать предыдущий пример с 1 вместо 0:

enum Color {Red = 1, Green, Blue};
let c: Color = Color.Green;

Или даже задать значения для всех членов:

enum Color {Red = 1, Green = 2, Blue = 4};
let c: Color = Color.Green;

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

enum Color {Red = 1, Green, Blue};
let colorName: string = Color[2];
alert(colorName);

Приведение типов (Type assertions)

Иногда вы попадаете в ситуацию, когда знаете больше о значении переменной, чем Typescript. Обычно это случается, когда вы знаете, что тип некоторой сущности может быть более специфичным, чем ее текущий. Type assertions - это способ сказать компилятору "поверь мне, я знаю, что делаю". Type assertion это как приведение к типу в других языках, но оно не делает никаких специальных проверок или реструктуризаций данных. Приведение к типу не имеет никакого воздействия на этапе выполнения программы и используется только компилятором. Typescript предполагает, что программист сделает все необходимые проверки, которые потребуются. Приведение к типу может быть сделано двумя способами. Первый это использование синтаксиса угловых скобок:

let someValue: any = "this is a string"; 
let strLength: number = (<string>someValue).length;

И другой - использование ключевого слова as:

let someValue: any = "this is a string"; 
let strLength: number = (someValue as string).length;