Skip to content

Latest commit

 

History

History
1121 lines (892 loc) · 61.2 KB

TypeScript.md

File metadata and controls

1121 lines (892 loc) · 61.2 KB

Шпаргалка по TypeScript

Общая информация

  • Разрабатывается с конца 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
    • Оптимизация 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];


Наполнение параметров (...)


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, удалив из него типы Keys
  • Exclude<UnionType, ExcludedMembers> — создаёт тип на основе списка типов UnionType, исключая из него все типы ExcludedMembers
  • Extract<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



Ссылки



Legmo, 2019-2023