Typescript Flashcards
aliases/type
aliases/type - приминяется для создания своего типа.
type myBoolean = false | true;
Union
Union - это мощный механизм, позволяющий создавать из множества существующих типов логическое условие, по которому данные могут принадлежать только к одному из указанных типов. Записываються через прямую черточку.
type Status = ‘ok’ | ‘loading’| ‘error’,
Enum
Enum, это перечисления, которые позволяют разработчику определить набор именованных констант. TypeScript предоставляет как числовые, так и строковые перечисления. Компилица в JS как самовызывающая функция.
enum StatusCode {
ERROR = 500,
NOT_FOUND = 404,
NOT_AUTH = 403,
}
enum Grades {
Junior= ‘junior’,
Middle = ‘middle,
Senior = ‘senior,
}
interface Developer {
login: ‘string’,
skills: string[],
level: Grades,
const dev1: Grades = {
login: ‘Marus’,
skills: [‘Js’],
level: Grades.Junior
}
function gradeDeveloper(developer: { level: Grades }) {
switch (developer.level) {
case Grades.Junior:
developer.level = ‘middle’;
case Grades.Middle:
developer.level = ‘senior’;
case Grades.Senior:
console.log(‘You have reached the maximum level’);
}
}
interface
interface - это группа взаимосвязанных свойств и методов, которые описывают объект, но не обеспечивают реализацию или инициализацию этих свойств и методов в объектах. Поскольку обе эти структуры определяют, как выглядит объект, обе могут использоваться в TypeScript для создания объектов.
interface можно расширять
interface User {
readonly email: string;
readonly login: string;
password: string;
}
// readonly - юзер не может изменить имейл.
interface User {
isOline?: boolean;
}
interface Person {
readonly firstName: string;
lastName: string;
phone?: number;
yearOfBirth?: number;
}
interface Employee extends User, Person {
contract: string;
}
Чем отличается Aliases/type от interfase
Aliases/Type:
1. Когда хотим создавать примитивы, union, комбинации их пересечений все то что не является класическим объектом;
2. Не можем расширять явно обьявленые существующие типы. (Window)
Interfaces
1. Когда мы хотим расширять интерфейс в будущем;
2. Если мы создайом интерфейс для классов то мы не используем алиасы;
Сужение типов/narrowing
Тема которая раскрывает работу проверку типов, когда принимаемый проп может быть либо строкой либо объектом.
Раньше мы делали typeof и проверяли тип пример ниже:
function example1(x?: number | string) {
if (typeof x === ‘string’) {
x.toLowerCase();
} else if (typeof x === ‘number’) {
x.toFixed();
} else if (typeof x === ‘undefined’) {
console.log(‘not value’);
} else {
return x;
}
}
Проверяем на str так как null тоже объект
function example2(strs: string | string[] | null) {
// if (Array.isArray(strs)) {}
if (strs && typeof strs === ‘object’) {
strs.push(‘1’);
} else if (typeof strs === ‘string’) {
strs.toLowerCase();
}
}
Оператор instanceof проверяет, принадлежит ли объект к определённому классу. Другими словами, object instanceof constructor проверяет, присутствует ли объект constructor.prototype в цепочке прототипов object.
function example3(x: number[] | Date) {
if (x instanceof Date) {
x.getTime();
} else {
x.concat([]);
}
}
Когда функция принимает два метода, и нам нужно в зависимости от в ходящих данных вызвать нужный метод мы проверяем объект по ключу.
type Fish = { swim: () => void };
type Bird = { fly: () => void };
function move(animal: Fish | Bird) {
if (‘swim’ in animal) {
return animal.swim();
}
return animal.fly();
}
Что такое Type Guards
Это любое Сужение типов или когда у нас большая функция и нам приходится прописывать большую логику if else-ов для сужение типов, то зачастую эти проверки выносятся в отдельную функцию которая и называется Type Guards.
type Fish = { swim: () => void };
type Bird = { fly: () => void };
Создадим отдельну функцию
// as говорим TS что принимай pet как Fish
// что у него есть метод swim.
function isFish(pet: Fish | Bird): pet is Fish {
return (pet as Fish).swim !== undefined; } function move(animal: Fish | Bird) { if (isFish(animal) { return animal.swim(); } return animal.fly(); }
Что такое Asserts
Алтернатива Type Guards
asserts это утверждение типа as
type User = {
name: string;
displayName: string | null,
}
function assertDisplayName(user: User): asserts user is User & {displayName: string} {
if (!user.displayName) throw new Error(‘User has no displayName field’);
}
function logUserByDisplayName(user: User) {
assertDosplayName(user);
console.log(user.displayName.toUpperCase())
}
Как типизировать this
function myClakHandler (
this: HTMLButtonElement, - указываем тип елемента на кого ссылается this;
event: Event ) {
this.disabled = true;
}
Overloads
Есть пример:
function add(a: number | string, b: number | string): string | number {
return a + b; (подсвечивается как ошибка)
}
Логично понятно что мы возвращаем либо строку либо число и то и то действие мы можем совершить, но TypeScript ругается так как может быть ситуация где а - строкаб б-число.
Напомощь нам приходят перерузка. Мы описываем каждое поведение отдельно.
function add(a: number, b: number): number;
function add(a: string, b: string): string;
function add(a: any, b: any): any {
return a + b; (подсвечивается как ошибка)
}
в основной функции пишем тип any и все отлично.
Рекурсивные типы
Когда в type нам нужно вложить число либо масив чисел.
type NestedNumbers = number | NestedNumbers[];
const nums: NestedNumbers = [1, 2, [3, 4 , 5], [657, 11]]];
nums.push(1)
nums.push([1, 2, [23, 34]];
Тпереь мы можем добавлять как число так и масив масивов чисел.
ПРИМЕР С JSON В ВИДЕО 3.10
Оператор “!”
Означает что там точно данный тип. Можно написать что переменная
(word as string) word.toLowerCase()
а можно указать word!.toLowerCase()
Данный оператор хорошо использовать для тестирования, для создания прототипа. НА ПРОДАКШИНЕ НЕ ИСПОЛЬЗОВАТЬ!
Универсальные типы/Generic
Для чего нужны дженерики?
У нас была функция с перегрузкой:
function head(value: string): string;
function head(value: number[]): number;
function head(value: boolean[]): boolean;
function head(value:Date[]): Date;
function head(value: any): any {
return value[0];
}
Что бы упростить написание и не писать бесконечное количество перегрузок используют generic.
Синтаксис базового generic-а
Array<string>
string[]
Promise<number></number></string>
Как написать динамический тип данных:
type TypeFactory<T> = T;
type XType1 = TypeFactory<string> будет стринг
type XType2 = TypeFactory<number> будет number</number></string></T>
На функции это пишется так (Вариант стрелочной функции смотри в VSCode):
function toArray<T>(...arg: T[]) {
return arg
}
Мы говорим какой бы ты тип туда не передал он всегда будет возвращить масив передоваемых типов.</T>
переделаем выше указанный примера
function head(value: string): string;
function head<T>(value: T[]): T;</T>
function head(value: any): any {
return value[0];
}
В interface мы используем:
interface ModelData<T> {
title: string;
value: T; //number, string, [], boolean
}</T>
const obj1: ModelData<number> = {
title: 'asd',
value: 12,
}</number>
Как в дженериках ограничить вхожденный параметр
function len<T extends { length: number }>(arg: T): number {
return arg.length;
}
В данном примере мы ограничываем количество параметров. коворим что у нас принимается масив, строка, и только тот обект а поле котором есть length.
keyOf
Создат union передаваемых значений.
interface Tup1 {
brand: ‘ford’,
model: ‘focus3’
}
cons testt1: Tup1 -> brand, model;
Для создания расширение для функций мы можем использовать:
export function prop<T, U extends keyof T>(key: U, obj: T): T[U] {
return obj[key];
}