Typescript руководство на русском

Typescript 4.2 Definition Guide. Перевод на русский язык официальной документации.
Источник: nauchikus.github.io

Общее¶

  • Что такое и для чего нужен TypeScript

Экскурс в типизацию¶

  • Вступление
  • Система типов, тип данных, значимые и ссылочные типы
  • Связывание, типизация, вывод типов
  • Преобразование типов
  • Типизированные и нетипизированные языки программирования
  • Статическая и динамическая типизация
  • Сильная и слабая типизация
  • Явная и неявная типизация
  • Совместимость типов на основе вида типизации
  • Совместимость типов на основе вариантности

Синтаксические конструкции¶

  • Аннотация Типов

Типы¶

  • Базовый Тип Any
  • Примитивные типы Number, String, Boolean, Symbol, BigInt
  • Примитивные типы Null, Undefined, Void, Never, Unknown
  • Примитивный Тип Enum
  • Типы — Union, Intersection
  • Type Queries (запросы типа), Alias (псевдонимы типа)
  • Примитивные литеральные типы Number, String, Template String, Boolean, Unique Symbol, Enum
  • Object, Array, Tuple
  • Function, Functional Types
  • Interfaces
  • Объектные типы с индексными членами (объектный тип с динамическими ключами)

Классы¶

  • Модификаторы доступа (Access Modifiers)
  • Закрытые поля определенные спецификацией ECMAScript
  • Абстрактные классы (abstract classes)
  • Полиморфный тип this
  • Модификатор readonly (только для чтения)
  • Definite Assignment Assertion Modifier
  • Классы — Тонкости

Тонкости TypeScript¶

  • Различия var, let, const и модификатора readonly при неявном указании примитивных типов

Работа с типами¶

  • Операторы — Optional, Not-Null Not-Undefined, Definite Assignment Assertion

Типы¶

  • Обобщения (Generics)
  • Дискриминантное объединение (Discriminated Union)

Работа с типами¶

  • Импорт и экспорт только типа

Типизация¶

  • Утверждение типов (Type Assertion)
  • Защитники типа
  • Вывод типов
  • Совместимость объектных типов (Compatible Object Types)
  • Совместимость функциональных типов (Compatible Function Types)
  • Совместимость объединений (Union Types)
  • Типизация в TypeScript

Работа с типами¶

  • Оператор keyof, Lookup Types, Mapped Types, Mapped Types — префиксы + и —
  • Условные типы (Conditional Types)

Расширенные типы¶

  • Readonly, Partial, Required, Pick, Record
  • Exclude, Extract, NonNullable, ReturnType, InstanceType, Omit
  • Массивоподобные readonly типы, ReadonlyArray, ReadonlyMap, ReadonlySet

Синтаксические конструкции¶

  • Синтаксические конструкции и операторы

React¶

  • Типизированный React
  • Функциональные компоненты
  • Классовые компоненты
  • Универсальные компоненты
  • Типизированные хуки
  • Контекст (Context)
  • HOC (Higher-Order Components)

Синтаксические конструкции¶

  • Пространства имен (namespace) и модули (module)

Сборка¶

  • Настройка рабочего окружения
  • Сборка с использованием ссылок на проекты
  • Декларации
  • Публикация TypeScript

Компилятор¶

  • Опции компилятора

Последнее обновление: 09.01.2023

  1. Глава 1. Введение в TypeScript

    1. Что такое TypeScript

    2. Установка и компиляция из командной строки

    3. Первое приложение TypeScript в Visual Studio

    4. Настройки компиляции

    5. Файл конфигурации tsconfig.json

  2. Глава 2. Основы TypeScript

    1. Переменные и константы

    2. Параметры компиляции noEmitOnError и target

    3. Типы данных

    4. Функции

    5. Тип функции и стрелочные функции

    6. Объединения union

    7. Null и undefined

    8. Type assertion. Преобразование к типу

    9. Объекты

    10. Псевдонимы типов

    11. Массивы

    12. Кортежи

    13. Неопределенный набор и наполнение параметров функции

    14. Перечисление enum

  3. Глава 3. Объектно-ориентированное программирование

    1. Классы

    2. Наследование

    3. Абстрактные классы, методы и поля

    4. Модификаторы доступа

    5. Методы доступа get и set

    6. Статические поля и методы

    7. Интерфейсы

    8. Преобразование типов

    9. Обобщения

    10. Миксины

  4. Глава 4. Модули и пространства имен

    1. Пространства имен

    2. Создание и подключение модулей

    3. Работа с модулями

  5. Глава 5. Заголовочные файлы

    1. Работа с заголовочными файлами

    2. Заголовочные файлы для популярных библиотек

  6. Глава 6. Декораторы

    1. Декораторы классов

    2. Декораторы методов и их параметров

    3. Декораторы свойств и методов доступа

    4. Фабрики декораторов

  • Глава 1. Введение в TypeScript
    • Что такое TypeScript
    • Установка и компиляция из командной строки
    • Первое приложение TypeScript в Visual Studio
    • Настройки компиляции
    • Файл конфигурации tsconfig.json
  • Глава 2. Основы TypeScript
    • Переменные и константы
    • Параметры компиляции noEmitOnError и target
    • Типы данных
    • Функции
    • Тип функции и стрелочные функции
    • Объединения union
    • Null и undefined
    • Объекты
    • Псевдонимы типов
    • Type assertion. Преобразование к типу
    • Массивы
    • Кортежи
    • Неопределенный набор и наполнение параметров функции
    • Перечисление enum
  • Глава 3. Объектно-ориентированное программирование
    • Классы
    • Наследование.
    • Абстрактные классы, методы и поля
    • Модификаторы доступа
    • Методы доступа get и set
    • Статические поля и методы
    • Интерфейсы
    • Преобразование типов
    • Обобщения
    • Миксины
  • Глава 4. Модули и пространства имен
    • Пространства имен
    • Создание и подключение модулей
    • Работа с модулями
  • Глава 5. Заголовочные файлы
    • Работа с заголовочными файлами
    • Заголовочные файлы для популярных библиотек
  • Глава 6. Декораторы
    • Декораторы классов
    • Декораторы методов и их параметров
    • Декораторы свойств и методов доступа
    • Фабрики декораторов

YooMoney:

410011174743222

Перевод на карту

Номер карты:

4048415020898850

TypeScript — язык программирования, представленный Microsoft в 2012 году и позиционируемый как средство разработки веб-приложений, расширяющее возможности JavaScript

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

🤔 Начинать стоит с проблемы

Давайте поговорим о том, почему TypeScript вообще появился и почему так быстро стал популярен?🤔

Рассмотрим преимущества TypeScript:

  • Статическая типизация. Кто-то легко может засунуть строку вместо числа, там где числа быть не должно. Проблема давняя и её видал наверное каждый разработчик. Без статической типизации у языка появляется много проблем, когда продукт начинает расти.
  • Компиляция. TypeScript компилируется и проверяет ошибки. Это позволяет избежать некоторых ошибок ещё до проверки работоспособности самого решения! Если вы написали что-то не так, то TS сразу даст вам знать😊

  • Хорошая документация. TypeScript хорошо задокументирован. Чтобы вы не пытались найти, вы наверняка найдете это в официальной документации.

  • Транспиляция из коробки. Вы настраиваете компилятор ручками (с помощью конфигурации) и сами можете задать в какой стандарт нужно превратить ваш текущий код.
  • Полноценное ООП. Разработчики TypeScript смогли сделать то, что давно не могли сделать в JavaScript: сделать полноценное ООП с типами, интерфейсами, перечислениями и многим другим

Давайте плавно перейдем к обучению😊 Мы начнем с самого начала и закончим достаточно сложными темами, а по пути рассмотрим аспкеты данного ЯП, которые могут быть интересны многим😳

Спойлер: В статье очень много картинок. Если пользуетесь мобильным интернетом, то не тратьте лишний трафик и добавьте в «Прочитать позже»😉

Настоятельная рекомендация

Для того чтобы лучше увидеть код, просто нажмите на картинку, она увиличится и будет в высоком разрешении😊

🧱 1. Встроенные типы

Основным «строительным материалом» в TypeScript является тип. К слову TypeScript потому так и называется, потому что у него есть типы. Они созданы для того, чтобы заранее указать тип переменной и строго соблюдать его. В TypeScript есть встроенные типы, в основном мы будем пользоваться тремя: string, number, boolean. Мы будем разбирать все основы достаточно динамично, как минимум потому что в документации данные основы описаны более чем понятно. Те, кто уже знаком с JavaScript поймут код, так как он похож как две капли воды, единственное что может показаться необычным — то, что мы везде цепляем двоеточие с типом, но вскоре чувство инородности такой записи уйдет😊

Типы в TypeScript объявляются следующим синтаксисом

переменная: тип = значение

Мы можем присвоить любой тип, который есть в JavaScript:

Явно присваиваем типы переменным

Типы в TypeScript работают как и в любом строготипизированном языке. Если вы указали тип у переменной и присвоили ей несоответствующий тип, то компилятор выдаст ошибку и будет ругаться🤬

Как мы видим запись типов достаточно легкая. Такой подход позволяет явно указать тип переменной и строготипизировать её. Однако, TypeScript сам умеет определять типы. Если мы объявим переменную и сразу присвоим ей значение, то TypeScript все поймет и запись с двоеточием можно будет опустить:

TypeScript сам умеет определять типы исходя из инициализированного значения

Интересным фактом является то, что TypeScript, а точнее автодополнение, которое работает на tsserver (специальный сервер, который является LSP и будет давать вам подсказки по улучшению кода и автозавершению) будет ориентироваться именно на тип данных (кто бы мог подумать🗿). Именно поэтому например при попытке написать 123.toLowerCase(); вы не увидите никакой подсказки, а сам TypeScript подскажет вам, что вы что-то попутали👹 перепутали тип данных.

🤲 1.1. Объединение

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

Ответ: На такой кейс придумано объединение типов😊

Типы можно объединять, сам процесс так и называется объединение. Записывается он так:

переменная: тип1 | тип2 = значение;

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

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

Объединяем типы

Минусом объединения является то, что TypeScript не даст нам использовать методы, которые например есть только у number, или только у string. Сам компилятор не будет знать что находится внутри переменной и будет жаловаться, что мы делаем что-то не то (пытаемся вызвать метод, которого нет у типа number | string).

📦 1.2. Встроенные типы и неявная типизация

Вопрос: Но как типизировать переменную, которая например содержит дату? Что нам с ней делать?!

Ответ: Для таких случаев в TypeScript уже существуют встроенные типы из JavaScript.

Мы можем объявить дату вот так:

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

Как это работает? Просто инициализируйте переменную, при инициализации TypeScript сам подберет нужный тип. Учтите, что при инициализации типа — тип в будущем просто так нельзя будет поменять (без спец. ключевых знаков и слов).

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

Отлично! Мы уже разобрали типы, объединение типов, встроенные типы и неявное объявление типов! Все самое интересное впереди😎

🤔 2. Типизация функций

Вопрос: Мы научились типизировать переменные, но как типизировать функцию?

Ответ: Типизация функции построена точно также, как и типизация переменных. Мы просто указываем типы через двоеточие😊

Функции типизируются достаточно легко. Давайте подумаем, что такое функция?

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

В целом все что нам нужно понять, это то, что у функции почти всегда есть параметры и выходное значение😌

Соответственно, исходя из определения, над которым мы с вами только что подумали — нам нужно типизировать входные и данные и данные которые нам функция отдает (выходные).

Синтаксис достаточно легкий:

function имя(параметр: тип, параметр: тип, …): тип выходного значения {}

Давайте рассмотрим пример, где функция принимает два аргумента и отдает нам их сумму:

Объявим и типизируем функцию

Как мы видим параметрами являются числа (два слагаемых) и выходным значением функции является сумма (тоже число).

Давайте немного разнообразим наш пример. Теперь функция будет принимать имя и количество его повторений и отдавать строку с повторяющимся именем:

Как мы видим, тут первый параметр — строка, второй — число и отдается строка. Все достаточно просто😊

◀ 2.1. Стрелочные функции

Синтаксис для стрелочных функций нисколько не меняется. Просто теперь мы добавляем типы, вот и все😊

😜 2.2. Особые типы в TypeScript (void, never)

В TypeScript также есть два особенных типа, которые используются с функциями — void и never. Разберем их по очереди.

void — пустотный тип. Это тип, который используется для выходного значения функции, когда она ничего не возвращает.

Хороший вопрос: Зачем же нам указывать тип функции, если она ничего не возвращает?

Не менее хороший ответ😅: Все функции в JavaScript что-то возвращают ожидаете вы этого или нет..

Что я имею ввиду? Давайте выполним код в консоли:

  • Создадим пустую функцию
  • Выполним его

Можно открыть консоль в DevTools, а можно зайти на https://jsconsole.com и попробовать поэксперементировать там. Не имеет значение, ведь JS ясное дело везде отработает одинаково👻

Звучит как бред бешеного, но давайте сравним выходное значение данной функции с undefined:

Сравниваем выходные значения пустой функции с undefined

Собственно, это все что нам нужно было доказать.. Любая функция возвращает undefined, если у неё в return не передается никакого значения😳

Именно поэтому, когда мы ничего не возращаем в нашем методе, нам необходимо указать void, для того чтобы единственным возможным выходным значением было undefined😊

Явно типизируем выходное значение функции

Теперь поговори о never. never — тип, который вообще ничего не отдает🗿🗿🗿

Если в void можно поместить undefined (можно даже вот так:)

То, тип never вообще не разрешает помещать в себя значения. Это полезно, когда метод один раз запустится и не завершится до окончания выполнения программы или если метод прерывает обычный флоу (кидает ошибку):

🌪 2.3. Любое значение (any, unknown, object, Function)

После того как мы поговорили о void и never, которые в основном предназначены для функций — неплохо бы поговорить о any, unknown, object, которые предназначены в основном для переменных😊

any — любой тип. То чего боится каждый TypeScript-разработчик.

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

Переменная с типом any — это переменная, у которой включена динамическая типизация и для которой практически не действуют все преимущества TypeScript (ибо с такими переменными про проверку типов можно забыть), именно поэтому данного типа нужно избегать😉

Объявить переменную с any крайне легко. Достаточно просто объявить переменную и ничего в ней не инициализировать, при этом явно не указав тип:

Это конечно круто, но жутко небезопасно🥶 У такой переменной могут быть любые свойства и методы, что уж там, в этой переменной может твориться вообще черт знает что, может это вообще функциональное выражение внутри переменной, а может подключаемый модуль, кто знает?👺 Именно поэтому придумали более безопасный тип — unknown

unknown — неизвестный тип переменной, у которой нет свойств и методов (только из общего прототипа), однако её можно сравнивать логическими операторами. Когда дело касается чего-то неизвестного, что нужно только проверить только на существовование, то нужно использовать unknown:

object — ещё один интересный тип данных. Он предназначен для того чтобы дать не примитивный тип переменной.

Примитивными типами являются:

  • string
  • number
  • boolean
  • symbol
  • null

Все остальные типы являются нетривиальными и соответствуют типу object (не путайте с Object!!!):

Function — последний «особенный» тип, который представляет объект с методами bind, call, apply.

К слову, любая структура данных или функция в JavaScript является объектом.

В JavaScript функции являются объектами первого класса, то есть: они являются объектами и с ними можно взаимодействовать и передавать их точно так же как любой другой объект. Если быть точным, функции — это объекты Function.

Вопрос: Чем же отличается object и Function?

Ответ: Function отличается от object тем, что у объекта функции есть методы call, bind, apply😊

🔫 3. Явное преобразование типов

Явное преобразование типа переменной может понадобиться нам, когда мы один тип переводим в другой или нам нужны свойства и методы из другого типа. Рассмотрим подробнее👀

Допустим, что у нас есть вот такая простенькая верстка:

Наша цель примитивная до чертиков — считать инпут с id=»fname», как нам это сделать? Возьмем элемент по getElementById:

И.. У нас будет ошибка😔 Все потому что getElementById всегда возвращает нам тип HTMLElement, у которого в свою очередь нет свойства value🤨

К слову: getElementById, querySelector, querySelectorAll — всегда возвращают элемент из DOM-дерева с типом HTMLElement, потому что он является родителем всех других элементов

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

Многие привыкли записывать преобразование типа с помощью первой записи, потому что она чем-то напоминает дженерик (о том что это поговорим чуть позже), однако вторая запись, как мне кажется является более лаконичной, хоть и является простым синтаксическим сахаром (обе записи несут одинаковый смысл, просто торая — чуть яснее).

🎋 4. Структуры данных

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

4.1. 🌈 Массивы, кортежи и дженерики

Вопрос: Если у меня есть массив данных, как мне его записать с помощью типа?

Ответ: Для этого есть два варианта записи😊

Первый вариант записи является синтаксическим сахаром для второй. Вторая запись в свою очередь является дженериком😊 Ниже будет секция посвященная дженерикам👀

Мы можем явно не указывать типы данных, и тогда TypeScript сам найдет тип массива и присвоит его переменной:

Вопрос: Что же такое дженерики?🤔🗿Что делать, если я передаю аргумент с определенным типом и у меня должен быть выход с точно таким же типом

Ответ: Для таких случаев существуют обобщенные типы, это и есть дженерики😳

Давайте рассмотрим код, который берет аргумент одного типа и возвращает аргумент такого же типа:

В данном примере T и является нашим «любым типом». Главная прелесть дженериков в том, что мы отдаем значение с таким же типом, с каким были входные данные (хотя и не обязательно. Суть в том, что мы просто опирируем одинаковыми типами). И нам совсем не важно какого там типа входные данные.

Давайте напишем маленькую функцию. Она берет переменную с любым типом и отдает массив с таким же типом:

Вот мы и научились пользоваться дженериками🥳 Ничего сложного, достаточно просто запомнить, что они нужны, когда мы производим действия над сущностями с одинаковым типом😊

Также, стоит упомянуть про кортежи. Кортежи, это массивы фиксированной длины, которые можно использовать для разных целей:

Кортежи используются достаточно редко, однако они существуют как структура данных в JavaScript, их удобно типизировать в кастомных типах, которые мы рассмотрим в следующем разделе😊

Ещё мы должны рассмотреть перечисления🤔 Перечисления это структура которая используется (как не странно🗿) для перечисления свойств:

Можно представлять перечисления как массив, в котором пара «ключ : свойство» перевернуты — «свойство: ключ». По умолчанию все перечисления начинаются с нуля. Если бы мы в примере выше вывели DIRECTION.down, то выход был бы 1, DIRECTION.left — 2 и так далее. Все эти индексы можно задать и явно:

Однако, для перечислений также можно задавать и строки. Вот например перечисление с позициями:

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

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

Тип у данного объекта следующий:

type sub_arr = (number[] | string[])[];

🔗 4.2. Кастомные типы и объекты

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

Как мы видим создавать новые типы достаточно легко! Типы обычно создаются когда одни те же примитивы используются очень часто или когда нужно определенным типом обозначить определенную переменную.

Проведем интересный эксперимент🔬 Давайте объявим переменную и сразу же её инициализируем с объектом:

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

Интересно🤔 Давайте объявим тип с данными параметрами и попробуем задать его нашей переменной:

Это сработало!😊 Таким образом мы можем строго типизировать объекты😊

Кстати, если мы строго типизировали объект, то мы уже не сможем мутировать его😳 Мы не сможем добавлять в него новые свойства или методы, так как TypeScript вычислил тип во время иницилизации объекта🤔

Вопрос: А что если нам нужно добавить необязательный ключ к строго типизированному объекту?

Ответ: На этот вопрос есть решение — опциональные параметры.

Вопрос: А что если у меня есть специфический объект, где должны быть только строчные ключи и значения?

Ответ: Для этого можно использовать сигнатуру ключа.

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

{
[имя ключа: его тип]: тип значения
}

Приведем пример:

Кавычки к слову ставить везде не обязательно. Поставил специально, чтобы акцентировать, что все ключи являются строками😊

🤩 4.3. Интерфейсы

Интерфейсы — одна из ключевых фич в TypeScript, они позволяют круто типизировать классы, функции, объекты и все что только можно😊 Интерфейсы созданы для того чтобы давать разработчику удобный инструмент для типизации всего кода💫

По синтаксису они немного отличаются от типов:

interface название {
ключ: тип
};

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

Ответ: Практически нет. Ранее типы использовались для одних кейсов, а интерфейсы — для других кейсов. Ныне это два очень похожих решения по типизизации структур данных, однако различия все же есть😊

Возможности, которые есть у интерфейсов, но нет у типов:

  • Декларативное расширение (мерджинг)
  • Расширение интерфейсов

И всего-то?! 😅 Давайте рассмотрим сначала две данные фичи, а потом сравним как они реализованы у типов🤔

🔨 4.3.1. Декларативное расширение (мерджинг)

Если мы объявим два интерфейса с одинаковыми именами, то TypeScript автоматически «сплюснет» их в один:

Как мы видим два интерфейса с одинаковым именем стали одним целым. И теперь при использовании данного интерфейса TypeScript требует чтобы у объекта были свойства и из первого интерфейса и из второго одноименного😊 Удобно это или нет — решать вам. Я считаю что так легко можно запутаться, именно поэтому люди и придумали расширение😌

⚒ 4.3.2. Расширение интерфейса

Расширением интерфейса называется процесс, когда один интерфейс поглощает все свойства родителя и добавляет свои:

Само расширение происходит следующим образом:

interface название extends родитеский_интерфейс {
// ключи и типы
}

Вопрос: Это круто, что интерфейсы могут расширяться, но можно же расширить типы, верно?

Ответ: Можно, но никто так не делает, ибо это плохая практика😔

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

Вот пример расширения типа:

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

Вообще пересечение у типов работает немного странновато: так как два типа по сути являются подмножествами типа object, то пересечение у них полное (тоже самое что и object & object), а значит все свойства просто соединяются🤯

Проще всего объяснить пересечение и объединение на примере: Представьте, что у нас в двух комнатах есть собаки и кошки. Кошки мяукают, собаки гавкают. Если мы объединим их, то будут кошки или собаки. Так как мы теперь не знаем кто мяукает, а кто гавкает, то мы можем использовать только общие методы и свойства, например: ходить().

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

Кроме того некоторые правила у типов можно обойти с помощью объединения. Разработчик может ошибиться в операции, поставить по привычке | (оператор объединения), и тогда и вовсе второй объект станет валидным. Нам будет достаточно соответствия хотя бы с одним из типов (достаточно свойств из Person или Programmer):

При объединении и пересечении запомните простое правило:

  • Объединение — это всегда или
  • Пересечение — это всегда и

Подумайте над небольшой задачкой, что получится, если пересечь object & Date, а если пересечь Number & String (именно конструкторы), будет ли у них что-то общее, если нет, то почему, ведь общие методы же есть (call, apply, bind)?🤔

Запись с типами кажется сложнее, требуется разглядывать код и разбираться в операторах сложения и умножения для множеств (и/или).

Совет: Старайтесь использовать интерфейсы, если дело касается объектов и сложных структур данных. Используейте типы для создания алиасов (вторых названий) для примитивных типов или для типизации функций.

Типизация функций, кстати у объектов выглядит не очень, а вот у типов вполне себе лаконично:

Запись типизации для функции в интерфейсе выглядит очень инородно🥶

🎩 4.4. Классы

Классы в JavaScript являются синтаксическим сахаром для создания объекта, об этом даже написано в документации MDN😳

TypeScript предоставляет нам все те же классы, однако с некоторыми улучшениями, а именно:

  • Поля
  • Параметры только для чтения
  • Модификаторы доступа
  • Перегрузка конструкторов
  • Наследование классов, а также имплементация интерфейсов
  • Расширение классов
  • Дженерики в классах
  • Параметризированные свойства
  • Абстрактные классы и инстансы

Пройдемся по порядку😊

🌳 4.4.1 Поля, параметры только для чтения, модификаторы доступа

Ранее в JavaScript мы объявляли свойства следующим образом:

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

Единственный аспект, который стоит учесть: в TypeScript все поля нужно указывать заранее, перед тем как использовать их в конструкторе. После того как мы рассмотрим следующую задачку на JS, мы сразу же сможем посмотреть реализацию на TS😊

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

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

TypeScript позволяет сделать следующее:

Таким образом благодаря ключевому слову readonly мы смогли сделать так, чтобы AGE нельзя было изменять вообще нигде. Если мы попытаемся изменить его внутри класса, то TypeScript тут же начнет ругаться.

Круто!😎 Мы познакомились с первым ключевым словом — readonly, а также узнали что поля в TypeScript надо указывать перед тем как инициализировать их в конструкторе. readonly, к слову ведет себя абсолютно идентично const. Мы можем мутировать объект (например массив), который инициазирован с readonly, однако, мы не можем заменить сам объект полностью (перетереть его).

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

  • Для того чтобы поздороваться
  • Для того чтобы попрощаться
  • Секретный пароль🤭

Первые два будут публичные (методы, которые можно вызывать вне класса), а вот третий мы сделаем защищенным (protected). Вообще в TypeScript есть три модификатора:

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

Всего в TypeScript 3 модификатора доступа:

  • public — публичный модификатор (по умолчанию)
  • protected — модификатор, который позволяет использовать поле в пределах класса и дочерних классов
  • private — модификатор, который позволяет использовать поле только в пределах класса

На счёт дочерних классов — не стоит беспокоиться. Мы разберем это понятие чуть позже, а пока забудьте, это не столь важно🤗

Реализовать это на JavaScript вполне возможно:

На TypeScript это реализовать ещё проще:

Синтаксис с private — намного приятнее, не правда ли?

📈 4.4.2 Перегрузка конструкторов

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

Давайте попробуем это сделать на JavaScript:

Кажется у нас неприятности.. Наш конструктор начинает расти… Кроме того я добавил гарды для входных значений (ну, а вдруг что?!). Можно было бы отделаться JSDoc вместо гардов, но это не самый лучший способ.. В будущем нам возможно нужно будет сделать определение имени через сеттеры, а не пихать все в конструктор, но по заданию мы должны сделать перегрузку. Так как JavaScript её не поддерживает, то приходится выкручиваться🙄

Теперь попробуем сделать то же самое на TypeScript:

Как мы видим, в начале мы объявили два конструктора без реализации. Это для того чтобы при перезгрузке TypeScript выводил правильные подсказки. Последний (третий) конструктор описывает уже саму реализацию. Проверяем мы только на наличие самого параметра😊

😱 4.4.3. Имплементация интерфейсов и классов. Абстрактные классы.

Замечательно, мы уже дошли до имплементации интерфейсов! Вы заметили как вырос наш класс? Уже немного сложно по нему ориентироваться и изменять что-то в нем, тем более в будущем мы создадим классы профессий, а они тоже будут изменяться🥶

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

Я немного подчистил комменты и создал интерфейс, однако, тут невооруженным глазом заметно, что чего-то не хватает👁

Не хватает тут конструктора и приватных полей. Но почему?!

  • Приватные поля нельзя объявлять в интерфейсах. Они просто не созданы для этого.
  • С конструкторами та же история😔

Чтобы объявить конструкторы вне класса и присвоить стартовые значения переменных, были созданы абстрактные классы. Абстрактные классы это своего рода прородители для классов. Весь синтаксис заключается в том, чтобы написать abstract рядом с классом, и в самом классе не реализовывать никакого функционала:

Вопрос: А чего мы добились таким разделением?

Ответ: Теперь каждый класс, который наследуется от APerson обязан инициализировать методы sayHello и sayGoodbye, мы также избавились от инициализации name, которая была в дочернем классе. Огромным плюсом также является то, что теперь все классы, которые наследуются от нашего абстрактного класса будут иметь схожую структуру. Хорошей практикой является объявлять все публичные методы именно в абстрактном классе😊

Вы могли заметить, что в случае с интерфейсами мы использовали ключевое слово implements, которое буквально говорит компилятору, что все что есть в интерфейсе должно быть сделано внутри класса. Если бы мы применяли интерфейс к многим классам, то вполне возможно, что у нас бы было много одинаковых методов, которые мы бы писали из разу в раз. extends же в свою очередь расширяет дочерний класс. Он берёт все методы из родительского класса, проверяет есть ли там абстрактные методы и свойства, если есть то, заставляет их реализовать в дочернем классе, а также берет и выполняет за нас всю суетливую работу. В данном случае все тривиально, он просто инициализирует имя существа, но таких «общих» моментов в классе родителе может быть очень много, в этом нам и помогает абстрактный класс.

Стоит также упомянуть, что мы можем наследоваться и от обычного класса (расширяя его функционал), однако в обычном классе нам придётся переобъявлять методы, а тут мы просто инициализируем абстрактные методы, которые до этого не были реализованы😊

🤖 4.4.4. Дженерики и параметризированные свойства

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

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

Теперь про дженерики😊 Дженерики как мы уже знаем созданы для того чтобы обощать тип, тут происходит то же самое:

📦 4.5. Модули

Модули в TypeScript экспортируются с помощью нескольких способов:

♻ 4.5.1 CommonJS

Модули в CommonJS импортируются и экспортируются с помощью require и module.exports. CommonJS создан для Node.js и не поддерживается в браузере без специальных библиотек

Синтаксис достаточно простой:

Такие модули в основном используются для Node.js, а также Webpack. Они очень удобны для разделения модулей между файлами. Вам ничего не мешает экспортировать пару модулей в объекте.

Более того синтаксис в CommonJS один из самых простых в использовании, Node.js вообще использует его по умолчанию😊 CommonJS позволяет импортировать модули прямо внутри условий (что недоступно в некоторых системах загрузки модулей)

Можно экспортировать модули ещё более удобно без использования module.exports:

😌 4.5.2 ES6 модули

ES6 модули позволяют экспортировать и импортировать модули немного по-другому:

Также, ES6-модули позволяют экспортировать дефолтные модули — модули, которые будут отдавать по дефолту, если мы не укажем что именно экспортируем:

Данные модули можно использовать в браузере. Для этого достаточно импортировать все модули в ваш главный файлик (пусть будет main.js), а затем написать следующее в HTML-файле:

😍 4.5.3. Внешние модули

Ясное дело, что мы будем использовать не только свои модули в нашем приложении. Часто нам приходится работать с модулями из NPM. Но, что будет, если мы их импортируем?

В данном случае мы попытались скомпиплировать программу и сразу получили предупреждение о том, что у нас нет поддержки ноды для TypeScript. Все расширения модулей для TypeScript начинаются с @types. Установим нужный модуль и посмотрим что будет дальше:

Программа скомпилировалась, круто😎 Теперь давайте попробуем поработать с самим кодом:

Наш модуль импортировался, но у него тип any!!! Поддержка сторонних модулей в TypeScript что невозможна?! Никак нет😊 Нам нужно просто скачать расширение для нашего плагина, которое тоже начинается на @types. В данном случае @types/ws. Установили и… Опять та же беда(((

Однако, если мы используем немного другую запись (ES6-модули), то все заработает:

Вот и все мы рассмотрели основные аспекты данного ЯП. В будущем будет ещё одна статья, но уже поменьше😅 про конфигурацию проектов и файлы декларации, где мы уже будем смотреть на примере проекта как правильно и красиво настроить файлы с типами в TypeScript😊

Если вам было интересно читать данную статью, то вы можете перейти на мой канал в телеге, там много всего интересного!😳 Приятно было рассказать об этом прекрасном ЯП, в будущем ещё не раз увидимся😊

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

В первую очередь возникает вопрос: а какие преимущества у этого языка?

  1. Статическая типизация. JavaScript — это язык с динамической типизацией, то есть компилятор не знает, что за тип переменной вы используете, пока эта переменная не будет инициализирована. Подобные вещи могут вызвать трудности и ошибки в ваших проектах. В TypeScript появляется поддержка статической типизации, что при грамотном использовании исключает ошибки, связанные с ошибочной типизацией переменной. При этом динамическая типизация вовсе не пропадает, и ей можно пользоваться.
  2. Лучшая поддержка в IDE. Основным преимуществом языка TypeScript перед JavaScript является лучшая поддержка со стороны IDE, что включает Intellisense, информацию компилятора в реальном времени, отладку и многое другое. Также существуют различные расширения, которые помогают в процессе разработки.
  3. Доступ к новым возможностям ECMAScript. В TypeScript есть поддержка новых возможностей ECMAScript, поэтому можно разрабатывать приложения с помощью новейших инструментов, не волнуясь о поддержке их браузером.

В каких случаях стоит использовать TypeScript?

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

  1. В случае крупного приложения. TypeScript отлично подойдёт, если ваше приложение имеет большую архитектуру и кучу кода, а особенно если над этим приложением работают несколько разработчиков.
  2. В случае, когда вы и ваша команда знакомы с ЯП со статической типизацией. Команде стоит смотреть в сторону TypeScript, когда они хотят разрабатывать приложение на JavaScript и уже знакомы с Java или C#, ведь те являются языками со статической типизацией.

Установка TypeScript

Установить TypeScript совсем не сложно — достаточно загрузить его через пакетный менеджер npm и создать TypeScript-файл:

npm install -g typescript

После его установки можно сразу перейти к рассмотрению возможностей этого языка и его синтаксиса.

Типы переменных

Number

Все числовые переменные в TypeScript существуют в виде числа с плавающей запятой. Числовой тип получают даже двоичные и шестнадцатеричные числа:

let num: number = 0.222;
let hex: number = 0xbeef;
let bin: number = 0b0010;

String

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

let str: string = 'Hello World!';

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

let multiStr: string = `Двухстрочная
переменная`
let expression = 'Новое выражение'
let expressionStr: string = `Выражение str: ${ expression }`

Boolean

Куда же без одного из основных типов данных:

let boolFalse: boolean = false;
let boolTrue: boolean = true;

Присвоение типов

Основной способ присвоения типа переменной — написание его после самого имени переменной через символ :.

Одиночный тип переменной

Простой пример, где присваивается значение переменной типа String:

let str: string = 'Hello World'

Такой способ действителен для всех типов данных.

Мультитип переменной

Переменной можно присваивать несколько типов, перечисляя их через оператор |.

let multitypeVar: string | number = 'String'
multitypeVar = 20

В коде выше переменной назначается два типа: строчный и численный. Теперь переменной можно присваивать как текстовые данные, так и числовые.

Проверка типов

Ниже будут описаны два основных (на деле их существует больше) способа проверки типа переменной.

Typeof

Команда typeof работает только с базовыми типами данных. Это означает, что эта команда может определить только типы, описанные выше.

let str: string = 'Hello World!'
if(typeof str === "number"){
 console.log('Str — это число')
} else {
 console.log('Str — это не число')
}

В коде выше создаётся переменная типа String, а потом проверяется, является ли эта переменная числом (что, естественно, всегда будет возвращать false).

Instanceof

Это оператор, который работает почти так же, как typeof. Отличие только в том, что это оператор может определять не только базовые типы, но и собственные.

class Human{
 name: string;
 constructor(data: string) {
  this.name = data;
 }
}
let human = new Human('Gabriel')
if(human instanceof Human){
 console.log(`${human.name} человек`)
}

В коде выше создаётся собственный тип, а потом инициализируется переменная этого типа. Далее этот тип переменной сравнивается с типом Human, что, в данном случае, возвращает true.

Тип Assertions

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

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

Ключевое слово as

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

let str: any = 'Текстовая переменная'
let strLength = (str as string).length

В этом коде текстовая переменная str кастуется в тип String, а поэтому можно использовать параметр length (это сработает и без кастования, если есть соответствующее разрешение в настройках TSLINT).

Оператор <>

Выполняет абсолютно такую же работу, что и ключевое слово as.

let str: any = 'Текстовая переменная'
let strLength = (<string>str).length

Этот код работает идентично предыдущему — разница только синтаксическая.

Массивы

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

Создание массива

Используя []

Можно создать массив, написав после типа элемента оператор [], тем самым обозначив эту переменную как массив:

let strings: string[] = ['Hello', 'World', '!']

Этот код создает массив элементов String, содержащий 3 разных элемента.

Используя дженерики

Создать массив можно с помощью дженерик-типа (обобщённого типа), написав Array<Type>:

let numbers: Array<number> = [1, 2, 3, 4, 5]

Этот код создаёт числовой массив, содержащий 5 элементов.

Мультитипные массивы

Кроме того, здесь можно создавать массивы с элементами нескольких разных типов. Перечислять типы нужно через оператор |.

let stringsAndNumbers: (string | number)[] = ['Age', 20]

В этом коде создаётся массив, который может содержать как текстовые переменные, так и числовые.

Многомерные массивы

TypeScript поддерживает многомерные массивы — можно сохранять массивы в других массивах. Создать такой массив можно через множественный оператор [].

let numbersArray: number[][] = [[1,2,3,4,5], [6,7,8,9,10]]

Тут создаётся массив, элементами которого являются другие массивы, которые, в свою очередь, содержат числа.

Кортежи

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

let exampleTuple: [number, string] = [20, 'https://tproger.ru'];

В этом примере создаётся кортеж c числом на позиции 0 и текстовой переменной на позиции 1.

Внимание При некорректном присвоении элемента будет выбрасываться исключение.

Пример того, как делать не нужно:

let exampleTuple: [string, number] = [20, 'https://tproger.ru'];

Enum (перечисление)

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

Числовые константы

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

enum State{
 Playing = 0,
 Paused = 1,
 Stopped = 2
}

Такое же перечисление (где первое значение равно 0, второе — 1 и т. д.) можно добиться и таким кодом:

enum State{
 Playing,
 Paused,
 Stopped
}

Текстовые константы

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

enum State{
 Playing = 'PLAYING',
 Paused = 'PAUSED',
 Stopped = 'STOPPED'
}

Объекты

Объект в TypeScript является сущностью, которая содержит набор пар ключ-значение. Значение может быть переменной, массивом или даже функцией. Объект рассматривается как отдельный тип переменной, не относящийся к примитивным.

Создаётся объект в фигурных скобках:

const human = {
 firstName: 'Frank',
 age: 32,
 height: 185
};

В коде выше создаётся объект human с 3 разными парами ключ-значение.

А вот как создавать функцию в объектах:

const human = {
 firstName: 'Старец',
 age: 32,
 height: 185,
 greet: function(){
  console.log("Приветствую тебя, путник!")
 }
};

Собственные типы

В TypeScript есть возможность создавать свои типы, называемые алиасами (англ. alias). Создаётся собственный тип через ключевое слово type.

type Human = {firstName: string, age: number, height: number}

В примере выше создаётся собственный тип Human, содержащий 3 разных свойства. Пример создания объекта типа Human:

const human: Human = {firstName: ‘Franz’, age: 32, height: 185}

Аргументы функций и возвращаемые типы

В TypeScript можно передавать тип аргумента функций и указывать тип возвращаемого значения. Как это выглядит:

function printState(state: State): void {
 console.log(`The song state is ${state}`)
}

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

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

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

add(2, 5)
add(1) // "Error to few parameters"
add(5, '2') // "Error the second argument must be type number"

Опциональные (необязательные) аргументы

Аргумент функции можно сделать необязательным, поставив после него оператор ?. Вот как это выглядит:

function printName(firstName: string, lastName?: string) {
 if (lastName) 
  console.log(`Firstname: ${firstName}, Lastname: ${lastName}`);
 else 
  console.log(`Firstname: ${firstName}`);
}

В примере выше параметр lastName является необязательным, и если он не будет передан, компилятор не выдаст ошибку.

printName('Gabriel', 'Tanner')
printName('Gabriel')

Эти две строки будут исполнены без ошибок.

Значения по умолчанию

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

function printName(firstName: string, lastName: string = 'Tanner') {
 console.log(`Firstname: ${firstName}, Lastname: ${lastName}`);
}

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

Интерфейсы

Интерфейсы содержат свойства и методы кастомного типа, но не содержат их реализацию. Реализацию берёт на себя класс, реализующий интерфейс. Для ясности вот пример:

interface Person{
 name: string
}
const person: Person = {name: 'Gabriel'}
const person2: Person = {names: 'Gabriel'} // Тип Person не присваивается

В примере выше в первом свойстве реализуется интерфейс Person. Попытка реализации интерфейса в переменной person2 выбросит исключение.

Опциональные (необязательные) свойства

При реализации интерфейса можно реализовывать не все его свойства. Чтобы сделать свойство необязательным, после имени свойства нужно поставить оператор ?. Пример:

interface Person{
 name: string
 age?: number
}
const person: Person = {name: 'Frank', age: 28}
const person2: Person = {name: 'Gabriel'}

В этом коде создаются два свойства: обычное и необязательное. Теперь при реализации интерфейса в переменной person2 исключение вызываться не будет.

Read-only свойства

Такие свойства используются тогда, когда нужно изменять свойство только в самом начале, при реализации, а потом свойство становится доступным только для чтения. Для этого используйте ключевое слово readonly.

interface Person{
 name: string
 readonly id: number
 age?: number
}
const person: Person = {name: 'Gabriel', id: 3127831827}
person.id = 200 // Изменить значение уже не получится

Barrel

Barrel-файлы дают возможность свести нескольких экспортируемых модулей в один более удобный.

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

export * from './person';
export * from './animal';
export * from './human';

И после этого можно одной строкой можно импортировать все эти модули вместе:

import { Person, Animal, Human } from 'index';

Generic

Дженерики (англ. generics) позволяют создавать компоненты, которые совместимы с большим количеством типов, а не только с одним. Это делает компоненты более «открытыми».

Возможно у вас возникнет вопрос: а почему бы не использовать тип any для взятия сразу нескольких типов? Рассмотрев пример ниже, можно это легко понять.

Допустим, нужно создать какую-нибудь функцию, которая возвращает переданный ей параметр:

function dummyFun(arg: any): any {
 return arg;
}

Хоть any и является обобщающим типом, у него есть одно отличие. При использовании типа any у вас не получится узнать оригинальный тип передаваемой переменной.

Ниже приведён пример того, как можно это реализовать с помощью дженерика:

function dummyFun(arg: T): T {
 return arg
}

В этом коде используется generic-параметр T, тип которого можно будет захватить и в дальнейшем использовать.

Для более детального понимания generic-типов загляните в статью Generics and overloads от Charly Poly.

Модификаторы доступа

Модификаторы доступа управляют доступностью членов класса. TypeScript поддерживает 3 модификатора: public, private и protected.

public

Элементы с этим модификатором доступны отовсюду без каких-либо ограничений. Этот модификатор установлен по умолчанию.

private

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

protected

Элементы с этим модификатором доступны из класса, в котором они определены, и в подклассах/производных классах.

TSLINT

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

Установка

Установить TSLINT можно как локально, так и глобально:

npm install tslint typescript --save-dev npm install tslint typescript -g

Потом идёт инициализация его в вашем проекте:

tslint --init

После этого у вас появится файл tslins.json, в который можно будет вносить собственные правила.

Конфигурирование

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

{
"defaultSeverity": "error",
"extends": [
 "tslint:recommended"
],
"jsRules": {},
"rules": {},
"rulesDirectory": []
}

Добавлять правила нужно в объект rules:

"rules": {
 "no-unnecessary-type-assertion": true,
 "array-type": [true, "array"],
 "no-double-space": true,
 "no-var-keyword": true,
 "semicolon": [true, "always", "ignore-bound-class-methods"]
},

Просмотреть все доступные правила можно в официальной документации.

Перевод статьи «A crash course in TypeScript»

Понравилась статья? Поделить с друзьями:
  • Роль председательствующего в руководстве судебным разбирательством порядок в судебном заседании
  • Асептобром инструкция по применению в ветеринарии
  • Духовой шкаф электрический аристон инструкция по режимам на русском языке
  • Руководство вооруженными силами через органы управления министерства обороны осуществляет
  • Змейка рубика инструкция в картинках для детей