Август всё! Вся база закрыта 💪
По планам на август закрыл вообще всё, что задумывал. Месяц выжал на максимум!
Под конец решил закрыть ещё одну мелкую, но частую рутину — написал пару лёгких
Дальше — сентябрь и новые задачи. Всех с наступающим! 🔥
По планам на август закрыл вообще всё, что задумывал. Месяц выжал на максимум!
Под конец решил закрыть ещё одну мелкую, но частую рутину — написал пару лёгких
.bat скриптов для автоматизации. Теперь не нужно руками прописывать одни и те же команды в консоли: запустил батник, и он сам всё делает и пушит на GitHub. Мелочь, а время и нервы экономят знатно.Дальше — сентябрь и новые задачи. Всех с наступающим! 🔥
🔥1
Перевожу проект с JS на TS. Наконец-то нормальный автокомплит в шаблонах Vue и никаких гаданий по поводу структуры данных.
Паттерн Assert Exhaustiveness в TypeScript: заставляем TS искать баги за нас
Представь: у тебя есть union-тип статусов заказа или валют, и ты обрабатываешь их через
Чтобы этого избежать, используется паттерн Assert Exhaustiveness:
Представь: у тебя есть union-тип статусов заказа или валют, и ты обрабатываешь их через
if или switch. Что произойдет, если через полгода в проект добавят новый статус, а ты забудешь добавить его обработку в функцию? Код тихо вернет undefined и сломает интерфейс.Чтобы этого избежать, используется паттерн Assert Exhaustiveness:
type Currency = 'RUB' | 'USD' | 'EUR' // Добавили EUR
// Вспомогательная функция для проверки исчерпываемости
// "value: never" работает в редакторе , и подсвечивает ошибку, если не обработали вариант
function assertExhaustiveness(value: never): never {
// Работает на сервере
throw new Error(`Необработанный вариант: ${JSON.stringify(value)}`);
}
function getCurrencyChar(currency: Currency) {
if (currency === 'RUB') return '₽';
if (currency === 'USD') return '$';
// ТУТ TS ВЫДАСТ ОШИБКУ КОМПИЛЯЦИИ:
// Argument of type 'string' (EUR) is not assignable to parameter of type 'never'.
// TS буквально заставляет тебя написать еще один if для 'EUR'!
// Если все варианты обработаны, сюды доходит только 'never'
return assertExhaustiveness(currency)
}
❤1
Перегрузки функций в TypeScript:
Представьте, что функция может принимать разные варианты аргументов (например, просто
Если просто написать
Перегрузки функций решают эту проблему! Они задают четкое правило:
// Реализовываем перегрузку
function axios(url: string): string;
function axios(url: string, sett: { method: string }): number;
function axios(sett: { url: string; method: string }): string;
function axios(urlOrSett: string | {url: string, method: string}, sett?: {method: string}): string | number {
if (typeof urlOrSett === 'string') {
if (sett) {
return 200; // Case 2: url + sett => number
}
return 'Data from URL'; // Case 1: url => string
}
return 'Data from config'; // Case 3: config object => string
}
const a1 = axios('/url')
const a2 = axios('/url', { method: 'GET'})
const a3 = axios({url: '/url', method: 'GET'})
Представьте, что функция может принимать разные варианты аргументов (например, просто
string или объект настроек).Если просто написать
function axios(...): string | number, TypeScript вернет тип string | number при любом вызове. В итоге придется везде писать лишние проверки if (typeof ... === 'string')Перегрузки функций решают эту проблему! Они задают четкое правило:
Если передали аргументы типа A — возвращаем строго тип B, а не неопределенный union!
👍1
Дженерики в TypeScript делают код гибким, но иногда эту гибкость нужно ограничить. Для этого используется
В примере ниже мы явно говорим компилятору:
В итоге мы получили безопасную функцию, которая не принимает лишний мусор вроде
extends (Generic Constraints).В примере ниже мы явно говорим компилятору:
T может быть чем угодно, НО только из числа string или number.// extends сужает(ограничивает) типы данных в дженерике
// мы можем вызывать эту функцию только со строками или числами
function wrapInArray<T extends string | number>(value: T): T[] {
return Array.isArray(value) ? value : [value];
};
// Все работает
wrapInArray(1);
wrapInArray('hello');
// Ошибка: мы не можем вызывать с типом данных boolean
// wrapInArray(true);
В итоге мы получили безопасную функцию, которая не принимает лишний мусор вроде
boolean или объектов, сохраняя при этом точную типизацию возвращаемого значения. 🔥Репозиторий создан, окружение поднято — к работе готов! 🚀 Начинаем переписывать приложение с чистого HTML/JavaScript на Vue 🥳
Закрыл блок по Generics в TypeScript! 🚀
Сегодня полностью добил дженерики и разложил всё по полочкам в Obsidian.
Прошёл путь от базового синтаксиса до продвинутых вещей:
1) Generics в функциях, классах,
2) Ограничения (
3) Константные дженерики (
Двигаемся дальше! 💻🔥
Сегодня полностью добил дженерики и разложил всё по полочкам в Obsidian.
Прошёл путь от базового синтаксиса до продвинутых вещей:
1) Generics в функциях, классах,
type и interface2) Ограничения (
Generic Constraints) и связка с keyof, typeof, Exclude3) Константные дженерики (
<const T>) и их применение в типизации роутингаДвигаемся дальше! 💻🔥
Полезная кастомная утилита в TypeScript:
В TypeScript из коробки есть утилита
Чтобы не писать это каждый раз вручную, создаётся простой и универсальный дженерик
Как это работает:
1)
2)
3)
ValueOfВ TypeScript из коробки есть утилита
keyof, которая достаёт все ключи объекта в виде Union-типа. Но встроенной утилиты для получения значений нет.Чтобы не писать это каждый раз вручную, создаётся простой и универсальный дженерик
ValueOf:// Дженерик для получения всех типов значений объекта / интерфейса / типа
type ValueOf<T extends Record<string, unknown>> = T[keyof T];
Как это работает:
1)
extends Record<string, unknown> — ограничивает входящий тип T, разрешая передавать только объекты.2)
keyof T — получает Union всех ключей объекта.3)
T[keyof T] — возвращает Union всех значений, соответствующих этим ключам.Красота TypeScript + Замыкания в JS 💡
Разбирал пример на курсе и поймал классный инсайт о том, как красиво пересекаются JS-фундамент и система типов TS.
Написали фабричную функцию
В чём тут фишка:
1. Замыкание в JS: Вложенные функции
2. Замыкание в TS: На уровне типов происходит то же самое! Тип
3. const T (TS 5.0): Позволяет не писать
Получился идеальный автокомплит и полная типобезопасность без лишнего кода 🔥
Разбирал пример на курсе и поймал классный инсайт о том, как красиво пересекаются JS-фундамент и система типов TS.
Написали фабричную функцию
customService, которая принимает массив ключей:function customService<const T extends string[]>(keys: T) {
function save<D>(key: T[number], data: D) {
// logic...
}
function getData(key: T[number]) {
// logic...
}
return { save, getData }
}
const serviceUtils = customService(['userId', 'videoId']);
serviceUtils.save('userId', {});
serviceUtils.getData('videoId');
// serviceUtils.getData('postId') // Ошибка TS!
В чём тут фишка:
1. Замыкание в JS: Вложенные функции
save и getData удерживают доступ к области видимости customService даже после её выполнения.2. Замыкание в TS: На уровне типов происходит то же самое! Тип
T запекается при вызове внешней функции (['userId', 'videoId']), а внутренние функции через T[number] "замыкают" этот тип и превращают его в строго ограниченный Union 'userId' | 'videoId'.3. const T (TS 5.0): Позволяет не писать
as const при вызове функции. TS сам выводит массивы как точные readonly-кортежи.Получился идеальный автокомплит и полная типобезопасность без лишнего кода 🔥