Общая информация
-
Разрабатывается с конца 2012
-
Разрабатывается в Microsoft, но OpenSource
-
Андерс Хейлсберг — создатель таких языков как Delphi, C#
-
Angular 2+ и Vue3 полностью написаны на TypeScript
-
Что это
- Типизированное надмножество JavaScript — любая программа на JS является программой на TypeScript. Код на TS компилируется в JS.
- Строго типизированный и компилируемый язык (ближе к Java, C# и другим строго типизированным языкам).
-
Зачем
- Строгая типизация уменьшает количество потенциальных ошибок, которые могли бы возникнуть при разработке на JavaScript.
- Реализует в JS многие концепции, которые свойственны объектно-ориентированным языкам, как, например, наследование, полиморфизм, инкапсуляция и модификаторы доступа и так далее.
- Позволяет быстрее и проще писать большие сложные комплексные программы. Их легче поддерживать, развивать, масштабировать и тестировать, чем на стандартном JavaScript.
Новинки 2020-2023
-
2023 (TS 5.0)
- Функции-декораторы
- позволяют добавить дополнительное поведение классу, методу, свойству.
- Const для типов параметров функций
- можно работать с типом, который передаём в дженерик, как с литералом.
- Улучшения в работе с Enum
- при создании enum каждому его ключу присваивается числовое значение, соответствующее его порядковому номеру, начиная с 0.
- теперь при передаче значения которого нет в перечислении, появляется ошибка:
- все перечисления теперь рассматриваются как объединённые перечисления
- Поддержка нескольких конфигурационных файлов
- теперь можно подключать N сторонних конфигурационных файлов, указав путь до них в поле
extends
- теперь можно подключать N сторонних конфигурационных файлов, указав путь до них в поле
- Оптимизация TS
- ускорение работы и установки TS
- Функции-декораторы
-
2022 (TS 4.9)
- Оператор
satisfies
- проверка соответствие выражения некоторому типу, не меняя сам тип. Помогает при работе с объектами со смешанными типами данных.
- Оператор
in
вызывает меньше ошибок- теперь вызывает меньше ошибок при сужении типов.
In
решает вопросы при проверке наличия св-ва у объекта и отделения этих типов друг от друга.
- теперь вызывает меньше ошибок при сужении типов.
- Использование ключевого слова
auto-accessor
в классах- синтаксический сахар для создания get и set методов приватного свойства.
- Прямое сравнение с
NaN
теперь запрещено, выдает ошибку - Новы команды управления импортами в редакторе кода
- "Удалить неиспользуемые импорты" (Remove unused imports)
- "Сортировать импорты" (Sort imports)
- Улучшение производительности
- Оператор
-
2020-2022
- Утилиты типов / Utility types
- Условные типы / Conditional types
- Вывод типов с помощью условных типов
- Необязательные и прочие (rest) элементы кортежа
- Абстрактные классы / Abstract classes
- Сигнатуры конструктора / Construct signatures
- Утилита типа ConstructorParameters
- Типы вариативных кортежей / Variadic tuple types
- Помеченные элементы кортежа / Labeled tuple elements
- Вывод типа свойства класса из конструктора
- Поддержка тега deprecated JSDoc
- Типы шаблонных литералов / Template literal types
- Рекурсивные условные типы
- Поддержка тега see JSDoc
- explainFiles
- Явное определение неиспользуемых переменных
- Разделение типов аксессоров
- override
- Статические сигнатуры доступа по индексу / Static index signatures
- Поддержка тега link JSDoc
- exactOptionalPropertyTypes
- Утилита типа Awaited
- Модификатор type в именованном импорте
- Утверждения const / const assertions
- Автозавершение методов классов
- Улучшение вывода типов при доступе по индексу
- Флаг CLI --generateTrace
- Поддержка модулей ES в Node.js
- Поле type файла package.json
- Выражения инстанцирования / Instantiation expressions
- extends и infer
- Опциональные аннотации вариативности для параметров типов
- Кастомизация разрешения модулей
- Переход к определению источника / Go to source definition
-
Ссылки
Отличия от JS
-
явное статическое назначения типов
-
Классы
— полноценные, как в традиционных ООП языках. В JS классы сейчас чисто «синтаксические» — под капотом прототипы -
Модули
-
private
(приватные переменные) - свойства полностью недоступны вне класса. Скоро будут внедрены в JS (символ#
) -
Декораторы
— позволяют добавить к классам и их членам метаданные и тем самым изменить их поведение без изменения их кода. (символ@
). В JS существовали давно, но для них нет спец. синтаксиса. Обещают скоро добавить. -
Интерфейсы
- -
namespace
(пространства имен) - способ логически сгруппировать код. Содержат группу классов/интерфейсов/функций/других пространств имен, которые могут использоваться в некотором общем контексте. Чтоб случайно не загрязнять глобалоное пространство имён -
Позже было добавлено в JS
Optional Chaining
(опциональная последовательность) - возможность безопасно обращаться к глубоко вложенным свойствам объекта без необходимости проверять существование каждого из них (оператор?
).Nullish Coalescing
(оператор нулевого слияния) - возможность проверки значенияnullish
(null или undefined) вместоfalsey
('', 0, undefined, null, false, NaN и т.д.)
-
Ссылки
Утиная типизация
- Неявная типизация, латентная типизация или утиная типизация (Duck typing)
- Концепция: конкретный тип или класс объекта не важен, важны лишь свойства и методы этого объекта.
- Т.е. при работе с объектом его тип не проверяется — проверяются свойства и методы этого объекта.
- Смысл «утиной типизации» — в проверке необходимых методов и свойств.
- Например: можно проверить, что объект — массив, не вызывая
Array.isArray
, а просто уточнив наличие важного для нас метода (напримерsplice
). - Если объект похож на дату, у него есть методы даты, то будем работать с ним как с датой (какая разница, что это на самом деле).
- То есть мы намеренно позволяем передать в код нечто менее конкретное, чем определённый тип, чтобы сделать его более универсальным.
- Этот подход добавляет гибкости коду, позволяет полиморфно работать с объектами, которые никак не связаны друг с другом и могут быть объектами разных классов. Единственное условие, чтобы все эти объекты поддерживали необходимый набор свойств и методов.
- Такая типизация характерна для языков программирования с динамической типизацией.
- «Если это выглядит как утка, плавает как утка и крякает как утка, то это, вероятно, и есть утка. »
Транспиляция
-
Конвертация кода в другой, похожий язык.
-
«Перевод» программы с одной версии языка на другую. Или на другой язык.
-
преобразование программы, написанной на одном языке программирования в качестве исходных данных, в эквивалентный код другой версии этого языка или в другой язык программирования того же уровня абстракции.
-
Преобразование моего кода, в другой, который может применяться и работать у конечного пользователя на любых устройствах с любыми версиям языка разработки.
-
Babel = транспилятор. Преобразует JSX в обычный JS, новый JS в старый, LESS/SCSS в CSS, TS в JS.
-
Компоненты написанные на JSX (HTML и JS) преобразуются в чистый JS с помощью CLI (интерфейс командной строки) инструмента Babel
-
Это важная часть фронтенд-разработки: поскольку в браузерах медленно появляются новые фичи, были созданы языки с экспериментальными возможностями, которые транспилируются в совместимые с браузерами языки.
-
Превращение одной версии языка в другую версию языка. JSX - это расширение JS, nfr xnj JSX->JS = транспиляция.
-
Компиляция
— перевод на другой язык (чаще всего низкоуровневый = байт-код). -
Ссылки
Типы переменных *
-
number
— числа -
string
— строки, в т.ч. шаблонные -
boolean
— логическое значение -
symbol
— symbol в js -
null
- null в js (в js typeof null = object, так сложилось исторически) -
undefined
— undefined в js -
never
— ТS only. Представляет отсутствие значения. Для типизации ответа функций, которые генерируют или возвращают ошибку. Или если в функции бесконечный цикл -
void
— ТS only. Определят отсутствующие типы. Для типизации ответа функций, которые не возвращают ничего (нет return) -
object
— -
array
— массивы (number[] илиArray<number>
) -
tuple
— кортежи. Массивы в которых могут быть разные типы данных (let x: [string,number]) -
enum
— перечисления. Задание понятных имён набору численных значений -
any
— что угодно (ключевое слово) -
Function
— представляет объект с методами bind, call, apply. -
Alias
— псевдоним для своего типаUnion
— означает «A или B» подобно OR-оператору||
в JS. mediem.com — TypeScript: основы -
Discriminated
— присвоение общего ключа, предназначенного для совместного использования внутри типа Union. mediem.com — TypeScript: основы -
Intersection
- надалог «AND» (&
) -
Inference
— автоматическое определние типа, если тип не указан в переменной или функции. -
Assertion
— «as». Позволяет переопределять Inference любым способом. Обычно используется для переноса кода из JS. Рекомендуется, когда мы точно знаем тип возвращаемой функции или тип переменной. -
Ссылки
type (Псевдонимы типов). Allias *
type id = number | string;
- псевдоним = Allias
- полезны для работы со сложными объектами
{name: string; age: number}
& (Расширения)
- В одном типе можно заимствовать или расширять код других типов, при помощи операции
&
-
type Person = {name: string; age: number}; type Employee = Person & {company: string};
Union (Объединения)
a | b
— позволяет комбинировать или объединить другие типы
? (Опциональные аргументы)
let person: { name: string; age?: number };
— свойство age необязательное
Typeof (Определение типа) *
- Команда (оператор)
typeof
работает только с базовыми типами данных.
Instanceof (Определение типа)
- Работает почти так же, как
typeof
. Отличие в том, что может определять не только базовые типы, но и собственные..
Type assertion. As (Преобразование к типу)
- модель преобразования значения переменной к определенному типу
- есть две формы приведения
- с применением оператора
as
:const header = document.getElementById("header") as HTMLElement;
- угловыми скобками:
const header = <HTMLElement>document.getElementById("header");
. Перед значением в угловых скобках указывается тип, к которому надо выполнить приведение. Так, в данном случае мы получаем объект типа HTMLElement
- с применением оператора
- такие преобразования будут иметь силу, если мы точно знаем, что значение может быть преобразовано к целевому типу.
- Например, на странице есть элемент с id=header, поэтому мы можем преобразовать значение к типу HTMLElement. Если такого элемента нет, то во время выполнения мы получим ошибку.
Оператор in
- Оператор in позволяет проверить наличие определенного свойства в объекте. Он возвращает true, если свойство есть в
объекте, и false, если свойство отсутствует
-
function printUser(user: { name: string; age?: number }){ if("age" in user){ console.log(`Name: ${user.name} Age: ${user.age}`); } else{ console.log(`Name: ${user.name}`); } }
-
Массивы *
тип_элементов_массива[]
илиArray<тип_элементов_массива>
- являются строго типизированными. Если изначально массив содержит строки, то в будущем сможет работать только со строками.
- с помощью индексов можно обращаться к элементам массива.
- ReadonlyArray - тип массивов, элементы которых нельзя изменять.
ReadonlyArray<тип_элементов_массива>
const people: ReadonlyArray<string> = ["Tom", "Bob", "Sam"];
const people: readonly string[]= ["Tom", "Bob", "Sam"];
- массивы поддерживают декомпозицию на константы и переменные. metanit.com
Tuples - Кортежи
- Массивы, которые могут хранить значения разных типов.
let user: [string, number];
- Кортежи могут иметь необязательные элементы, для которых можно не предоставлять значение. Чтобы указать, что элемент является необязательным, после типа элемента ставится
?
-
let bob: [string, number, boolean?] = ["Bob", 41, true]; let tom: [string, number, boolean?] = ["Tom", 36];
-
- многоточие - С помощью оператора
...
внутри определения типа кортежа можно определить набор элементов, количество которых неопределено. Например:-
let math: [string, ...number[]] = ["Math", 5, 4, 5, 4, 4]; let physics: [string, ...number[]] = ["Physics", 5, 5, 5];
-
- readonly - позволяет создавать кортежи только для чтения, элементы которого нельзя изменить
const tom: readonly [string, number] = ["Tom", 36];
Наполнение параметров (...)
- TS позволяет использовать массивы для передачи данных сразу нескольким параметрам.
-
const numbers = [1, 3, 5, 7, 9] as const; let num = sum(...numbers);
- Ссылки
Enum (Перечисления)
-
Общее
-
Задание понятных имён набору численных значений
-
enum Directions { Up, //0 Down = 1, Left = 4, Right, //5 }
-
можно получать ключ по значению (
Directions.Up // 0
,Directions['Up'']
) -
можно получать значение по ключу (
Directions[0] // 'Up'
) = Reverse Enum -
можно задавать свои индексы вместо чисел
-
enum Links { vk = 'https://vk.com/', facebook = 'https://facebook.com/', youtube = 'https://youtube.com/', }
-
теперь
Links[0]
илиLinks['https://vk.com/']
не сработает -
сработает
Links.vk
илиLinks['vk']
-
-
Константные перечисления
- ссылки к enum всегда выполняются как доступы к свойству, и никогда не встраиваются.
- Т.е. написав enum, и описав его перечисляемые значения вы всегда получите генерацию объекта через функцию. Даже если этот объект не будет использоваться
- если надо оптимизировать ресурсы и мощности - используем константные перечисления. Тогда мы получим соответствующие значения только при обращении к опр. элементу enum.
- Генерации объекта при этом не происходит
-
const enum Links { vk = 'https://vk.com/', facebook = 'https://facebook.com/', youtube = 'https://youtube.com/', }
- позволяет определить набор именованных констант, которые описывают определенные состояния.
- существует возможность создавать текстовые и числовые константы.
Generic (Дженерики, Обобщения, Общие типы)
-
Общее
-
Позволяют создавать компоненты способные работать с разными типами, но без использования
any
. -
Можно создавать компоненты, которые совместимы с большим количеством типов, а не только с одним.
-
«Захватываем» тип аргумента, потом используем его для описания типа возвращаемого из функции.
-
Если в функции пришла строка - функция должна вернуть строку.
-
Обычно используют букву
T
(type), но вообще-то можно любую. -
Чаще всего используются в функциях.
-
Почему не использовать тип
any
для взятия сразу нескольких типов?- Допустим, нужно создать какую-нибудь функцию, которая возвращает переданный ей параметр:
function dummyFun(arg: any): any {return arg;}
- Хоть
any
и является обобщающим типом, у него есть отличие: мы не можем узнать оригинальный тип передаваемой переменной. - Это можно реализовать с помощью дженерика:
function dummyFun(arg: T): T {return arg}
- В этом коде используется generic-параметр T, тип которого можно будет захватить и в дальнейшем использовать.
- Допустим, нужно создать какую-нибудь функцию, которая возвращает переданный ей параметр:
-
Что делать, если я передаю аргумент с определенным типом и у меня должен быть выход с точно таким же типом
- Для таких случаев существуют обобщенные типы, это и есть дженерики
- нужны, когда мы производим действия над сущностями с одинаковым типом
-
-
Примеры
-
//используя any const getter1 = (data: any): any => data; //используя generic const getter2 = <T>(data: T): T => data; getter1('test').length // 4 getter1(10).length // undefined getter2(10).length // Error - у числа нет метода length. Получили ошибку ещё на этапе написания кода //можно при вызове функции указать какой тип данных будет получать функция, //чтоб случайно не впихнуть туда "не то" getter2<string>('test').length
-
//generic + класс + два типа данных class User<T, K> { constructor(public name: T, public age: K) { } public getPass(): string { return `${this.name}${this.age}` } } const Ivan = new User('Ivan', '31'); const Petr = new User(123, 27); const Efim = new User('Efim', 15); Ivan.getPass(); // "Ivan31" Petr.getPass(); // "12327" Efim.getPass(); // "Efim15"
- Если надо поставить ограничение на generic-тип, напримре указать что он должен быть только числом
-
class User<T, K extends number> { //... }
- Можно создать массив можно с помощью дженерик-типа написав
Array<Type>
-
let numbers: Array<number> = [1, 2, 3, 4, 5]` Этот код создаёт числовой массив, содержащий 5 элементов.
-
Интерфейсы
-
Общее
- Особый тип данных. Нужны для именования типов.
- Создавая интерфейс мы создаем новый тип данных (чаще всего для объектов или классов).
- Этому типу мы указываем какие поля, функции и какие вообще элементы должны будут присутствовать у объектов данного типа.
- Интерфейсы содержат свойства и методы кастомного типа, но не содержат их реализацию.
- Реализацию берёт на себя класс/объект, реализующий интерфейс.
- Type создаёт псевдоним для любых типов (примитивы и т.д.).
- Интерфейс = именованный тип объекта/класса.
- Интерфейс может наследоваться и расширяться другими интерфейсами (использован в выражениях
extands
илиimplements
). - В принципе можно использовать только типы или только интерфейсы.
- Но, сематически правильно — использовать интерфейсы для объекта/классов, а типы для остального.
- Особое значение то имеет в ООП-подходе.
-
Преимущества интерфейсов перед типами
- Декларативное расширение (мерджинг) — если объявить два интерфейса с одинаковыми именами, то TS "склеит" их в один.
- Расширение интерфейсов — когда один интерфейс поглощает все свойства родителя и добавляет свои.
-
interface Person { name: string }; const person1: Person = {name: 'Gabriel'} const person2: Person = {surname: 'Grasia'} // Ошибка, нет обязательного св-ва name + есть лишнее св-во surmane
- В примере выше в первом свойстве реализуется интерфейс Person.
- Попытка реализации интерфейса в переменной
person2
выбросит исключение.
-
Возможности
age?: number
— опциональные свойства. Если такой пометки нет - св-во обязательно.readonly age: number
— свойство только для чтения. Не может быть изменено.[propNameL string]: any
— строковый индекс. Позволяет добавлять любое количество свойств любого типаclass Ivan impelement User, Admin{...}
— создание класса на основании нескольких интерфейсовinterface SuperAdmin extends Admin{...}
— класс SuperAdmin расширяет класс Admin, т.е. добавляет новые св-ва/методыinterface SuperAdmin extends User, Admin{...}
— класс SuperAdmin расширяет классы Admin и User
Классы
-
Ссылки
- В ООП класс — шаблон для создания объектов, обеспечивающий начальные значения состояний: инициализация полей-переменных и реализация поведения функций или методов.
- Инструкция, чертёж по которому можно создать автомобиль (объект).
- В JS класс — функция для создания объектов. Определяет св-ва и методы объекта.
-
Примеры
- Полная форма записи:
-
class User { //объявлем поля класса - т.е. типизируем св-ва класса + можем задать начальные значения public name: string; private nickName: string; protected age: number = 20; //задано дефолтное значение readonly pass: number; static secret: number = 12345 //статическое св-во, видно в самом классе без создания экземпляра. // Доступно всем экземплярам через User.secret (не this.secret) constructor(name: string, nickName: string, age: number, pass: number) { //добавляем возможность принимать эти св-ва при инициализации this.name = name; this.nickName = nickName; this.age = age; this.pass = pass; } }
- Сокращенная форма записи:
-
class User { constructor( public name: string, private nickName: string, protected age: number = 20, //задано дефолтное значение readonly pass: number, ) {} }
-
4 модификатора доступа
- управляют доступностью к свойствам класса
public
— значение по умолчанию. Можно получить свободный доступ.private
— не доступен за пределами класса. Ни классам-наследникам, ни объектам созданным с помощью данного классаprotected
— доступен только наследникамreadonly
— доступен только для чтения
-
Отличия классов TS и JS
- TS предоставляет нам те же классы JS, но с некоторыми улучшениями:
Поля
— переменные уровня класса, только для их объявления не применяются var и let- объявляю в самом вверх при создании класса.
Модификаторы доступа
— public, private, protected, readonlyПараметризированные свойства
— можно сразу объявлять св-ва в конструкторе (не объявлять их вначале).Перегрузка конструкторов
— способ обойти правило «один конструктор в классе».- Он один, но можно использовать его со многими различными типами параметров.
Имплементация интерфейсов
— если класс реализует интерфейс, он обязательно должен реализовать свойства и методы, определенные в интерфейсе.class User implements НазваниеИнтрейеса{ код класса }
Расширение
классов - поглощение всех св-в родительского класса + добавление своих.Дженерики
в классах - способ сообщить классу, какой тип необходимо использовать при его вызове.- Так же, как во время вызова мы сообщаем функции, какие значения использовать в качестве аргументов.
class User<T> {constructor(id:T){}}
- Так же, как во время вызова мы сообщаем функции, какие значения использовать в качестве аргументов.
Инстансы
— объекты, которые созданы при помощи класса (экземпляры)Наследование
классов - наследуем св-ва и методы родительского класса.class Admin extends User{ код класса }
Абстрактные классы
— базовые классы, от которых наследуются другие.
-
Аксессоры
- Это
геттеры
исеттеры
— спец. методы класса для установки и чтения его свойств. - Чтобы случайно не изменить св-ва классе, которые не должны меняться - стараются напрямую св-ва класса не менять.
- Используют геттеры и сеттеры.
- Снаружи ведут себя как свойства:
-
//Вызов обычного метода класса task.setSomethingData(10); //Вызов метода-сеттера task.somethingData = 10;
- Это
-
Абстрактные классы
-
Базовые классы, от которых наследуются другие.
-
В JS - это обычный класс. В TS - отдельная сущность.
-
Нужен чтоб прописать как должен выглядеть класс-потомок. Например, обязательно иметь св-во Х и метод Y, причём метод должен возвращать именно опр. тип данных.
-
Особенности
- от данного типа класса нельзя напрямую создать экземпляр. Можно только создать наследника
- абстрактный класс содержит детали реализации своих элементов (т.е. свойств и методов)
-
abstract class User { //... }
-
-
Наследование
- При наследовании класс-потомок перенимает весь функционал класса-родителя - все его свойства и функции и может их использовать.
- Производные классы могут переопределять методы базовых классов.
- TS поддерживает
одиночное наследование
— свойства и поведение базового класса могут быть унаследованы не более чем одним производным классом.- Он используется для добавления новых функций в уже реализованный класс.
многоуровневое наследование
— производный класс действует как базовый класс для другого производного класса.- Вновь созданный производный класс приобретает свойства и поведение других базовых классов.
Namespaces(Пространства имён)
-
Нужны чтоб не засорять переменными глобальную область видимости.
-
Альтернатива модулям или обычным классам со статическими свойствами.
-
Особая сущность, похожая на объект.
-
Чтоб получить снаружи доступ к данным из
namespace
— их надо из него экспортировать. -
namespace Utils { const userPass: string = '12345'; export const userName: string = 'Ivan'; } const myName = Utils.userName; //Всё ок const myPass = Utils.userPass; //Ошибка. Но можно создать тут свою константу myPass - никаких ошибок это не вызовет
-
Сами namespaces тоже можно импортировать/экспортировать из одного файла в другой, есть спец. синтаксис.
-
Но это устаревшая возможность. Рекомендуют использовать JS-модули.
-
Ссылки
Модули, barrel-файлы
-
Общее
-
Нужны чтоб не засорять переменными глобальную область видимости.
-
Модули создают своё пространство имён.
-
Модули выполняются в собственной области видимости, а не в глобальной. Это означает, что переменные, функции, классы и т.д., объявленные в модуле, недоступны за пределами - модуля до тех пор, пока они в явном виде не будут из него экспортированы. Кроме того, перед использованием экспортированных сущностей, их следует импортировать в - соответствующий
-
файл.
-
В TS, как и в JS ES6+, любой файл, содержащий
import
илиexport
верхнего уровня (глобальный), считается модулем. -
Файл, не содержащий указанных ключевых слов, является глобальным скриптом.
-
//File Utils.ts export const userName: string = 'Ivan'; //File User.ts import {userName} from './Utils' const fullName = userName + ' Ivanov';
-
-
Barrel-файлы
- Barrel-файлы дают возможность свести нескольких экспортируемых модулей в один более удобный. Для этого достаточно в проекте создать отдельный файл, который будет экспортировать несколько модулей сразу.
-
export * from './person'; export * from './animal'; export * from './human';
- И после этого можно одной строкой можно импортировать все эти модули вместе:
import { Person, Animal, Human } from 'index';
Декораторы
-
Общее
-
Декораторы позволяют добавить метаданные классам и функциям.
-
Тем самым изменить их поведение без изменения их кода.
-
По сути - обычная функция. Оборачивает некую сущность и модифицирует её поведение. Похоже на High Order Components.
-
//создаём декоратор класса const logClass = (constructor: Function) => { console.log(constructor) // если декоратор класса вернет значение, то он заменит объявление класса с помощью предоставленного конструктора }; @logClass //применили декоратор к классу User class User { //... }
-
-
4 типа декораторов
- класса
- свойства
- метода
- аксессора (геттеры/сеттеры)
-
Фабрика декораторов
-
Функция, которая возвращает выражение. Будет вызвана декоратором при выполнении программы.
-
function factory(bvalue: any) { //Factory return function (target: any) { //Decorator console.log(target) } }
-
-
Композиция декораторов
-
Можно применять несколько декораторов
-
//Вариант 1 @decoratorOne @decoratorTwo class User1 {/*...*/ } //Вариант 2 @decoratorOne @decoratorTwo class User2 {/*...*/ }
-
Выражение для каждого декоратора вычисляется сверху вниз.
-
Затем результаты вызываются снизу вверх.
-
Перегрузка функций. Overloading
-
Общее
Перегрузка функций
— возможность создавать несколько одноименных функций с разными реализациями.- При вызовах перегруженной функции будет выполняться конкретная реализация этой функции в соответствии с контекстом вызова, позволяя одному вызову функции выполнять разные задачи в зависимости от контекста
-
Примеры
-
Пример 1 — самый примитивный вариант
-
//Соединяет 2 или 3 строки в одну. Если передать только 1 строку - вернёт её же function concatString(s1: string, s2?: string, s3?: string) { let s = s1; if(s2) { s += `, ${s2}`; } if(s3) { s += `, ${s3}`; } return s; } // Это сработает concatString('one'); concatString('one','two'); concatString('one', 'two', 'three'); // Получим ошибки компиляции concatString('one', true); concatString('one', 'two', 'three', 'four');
-
Пример 2 — использование приёма «перегрузка»
-
//если передать строку - вренёт строку, иначе вернёт случайное число function helloWorld(): number; // первая перегрузка — описываем что функция может вернуть число function helloWorld(s: string): string; // вторая перегрузка Уточняем — функция может вернуть строку, если приняла строку function helloWorld(s?: string) { // Основная функция, должна принять все возможные перегрузки, объявленные ранее. if (!s) { return Math.random(); } return s; } // x имеет тип string const x = helloWorld('test'); // y имеет тип number const y = helloWorld();
-
-
Важен порядок объявления перегрузок
- Всегда помните о важности порядка объявления перегрузок:
- вначале объявляем наиболее специфические перегрузки, затем менее
- основная функция объявляется в последнюю очередь
- основная функция должна соответствовать всем вариантам описаных типов
- Всегда помните о важности порядка объявления перегрузок:
-
Избегать n перегрузок, отличающихся только конечными параметрами
-
//вместо этого interface Example { foo(one: number): number; foo(one: number, two: number): number; foo(one: number, two: number, three: number): number; } //делаем так interface Example { foo(one?: number, two?: number, three?: number): number; }
-
-
Избегать n перегрузок, отличающихся типом только в одном типе аргумента
-
//вместо этого interface Example { foo(one: number): number; foo(one: number | string): number; } //делаем так interface Example { foo(one: number | string): number; //можно обойтись одним модификатором optional }
-
Утилиты (Utility Types)
- Есть 16 типов утилит:
Partial<Type>
— сделать все члены объекта необязательнымиRequired<Type>
— тип все поля которого становятся обязательнымиReadonly<Type>
— тип все св-ва которого предназначены только для чтенияRecord<Keys, Type>
— создаёт тип с набором свойств Keys (определяем) типа Types (определяем)Pick<Type, Keys>
— создаёт тип на основе интерфейса Type, оставив в нём только свойств Keys. ФильтрацияOmit<Type, Keys>
— создаёт тип на основе интерфейса Type, удалив из него типы KeysExclude<UnionType, ExcludedMembers>
— создаёт тип на основе списка типов UnionType, исключая из него все типы ExcludedMembersExtract<Type, Union>
— конструирует тип, составляя в нём только переданные св-ваNonNullable<Type>
— выбрасывает из создаваемого типа все несуществующие типы (null и undefined)Parameters<Type>
ConstructorParameters<Type>
ReturnType<Type>
— создаёт тип, состоящий из возвращаемого функцией типаInstanceType<Type>
— создаёт тип, состоящий из типа экземпляра функции-конструктораThisParameterType<Type>
OmitThisParameter<Type>
ThisType<Type>
- Пример исполььзования:
-
interface Props { a?: number; b?: string; }; const obj1: Props = {a: 5} //Ok const obj2: Required<Props> = {a: 5} //Error. Не хвататет св-ва b.
- Ссылки
Типизация функций — пример
-
let MyFunc: (someArgName: string) => void; function otherFunc(name: string): void { alert(`Hello ${name}!`); }; myFunc = otherFunc