Дженерики в 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-кортежи.Получился идеальный автокомплит и полная типобезопасность без лишнего кода 🔥
Прокачиваю свои CLI-инструменты 🛠
Раньше для отправки кода на GitHub я пользовался обычным дефолтным
Что будет уметь новый скрипт:
⚙️ Интерактивное меню с выбором действий (
⚙️ Быстрый push с вводом кастомного коммита
⚙️ Первичная инициализация репозитория и привязка remote в один клик
⚙️ Быстрое создание и переключение веток.
На скрине сравнение старого скрипта и заготовки для нового. Допилю логику, поправлю пары мелочей и выложу готовый скрипт, если кому-то пригодится! 🔥
Раньше для отправки кода на GitHub я пользовался обычным дефолтным
.bat скриптом из трех команд. Но сегодня решил, что пора избавить себя от рутины, и начал писать полноценную интерактивную утилиту.Что будет уметь новый скрипт:
⚙️ Интерактивное меню с выбором действий (
choice + goto) ⚙️ Быстрый push с вводом кастомного коммита
⚙️ Первичная инициализация репозитория и привязка remote в один клик
⚙️ Быстрое создание и переключение веток.
На скрине сравнение старого скрипта и заготовки для нового. Допилю логику, поправлю пары мелочей и выложу готовый скрипт, если кому-то пригодится! 🔥
Media is too big
VIEW IN TELEGRAM
Добавил подтверждение перед
push и init, чтобы случайно ничего не запустить по ошибке. Показываю на видео, как теперь это работает!Добавил создание веток в свой
Продолжаю допиливать свой батник для автоматизации работы с Git. Вчера написал метку для создания новой ветки с автоматическим переключением на неё (
Что внутри метки
• Подтверждение действия через меню (
• Проверка на пустое имя ветки (чтобы скрипт не падал с ошибкой);
• Мгновенный переход в новую ветку и возврат в главное меню.
Код функции:
Мелочь, а рутину и консольные команды сильно сокращает. Постепенно собирается полноценное CLI-меню для удобной разработки 💻
git-helper.bat 🚀Продолжаю допиливать свой батник для автоматизации работы с Git. Вчера написал метку для создания новой ветки с автоматическим переключением на неё (
git switch -c).Что внутри метки
:create_branch: • Подтверждение действия через меню (
choice); • Проверка на пустое имя ветки (чтобы скрипт не падал с ошибкой);
• Мгновенный переход в новую ветку и возврат в главное меню.
Код функции:
:: Создание ветки и сразу переходим в нее
:create_branch
cls
echo === СОЗДАНИЕ ВЕТКИ (ПЕРЕКЛЮЧАЕМСЯ НА НЕЕ) ===
echo.
echo Создать новую ветку и перейти в нее? (Y/N)
choice /c YN /n /m "Ваш выбор: "
if errorLevel 2 goto menu
set branch_name=
set /p branch_name="Введите название новой ветки: "
if "%branch_name%"=="" (
echo [!] Имя ветки не может быть пустым!
pause
goto menu
)
git switch -c "%branch_name%"
echo.
echo [!] Вы успешно перешли в созданную ветку
pause
goto menu
Мелочь, а рутину и консольные команды сильно сокращает. Постепенно собирается полноценное CLI-меню для удобной разработки 💻
Добавил создание ветки БЕЗ перехода
Вдобавок к прошлой функции сделал метку для случая, когда ветку нужно просто создать в фоне, оставаясь в текущей (
Что нового в
• Вывод подсказки с нужной командой для перехода на будущее.
Код функции:
Теперь в скрипте закрыты оба базовых сценария работы с ветками 💻
Вдобавок к прошлой функции сделал метку для случая, когда ветку нужно просто создать в фоне, оставаясь в текущей (
git branch).Что нового в
:create_branch_only: • Вывод подсказки с нужной командой для перехода на будущее.
Код функции:
:: Создание ветки (остаемся в текущей)
:create_branch_only
cls
echo === СОЗДАНИЕ ВЕТКИ (ОСТАЕМСЯ В ТЕКУЩЕЙ) ===
echo.
echo Вы хотите создать ветку и остаться в текущей? (Y/N)
choice /c YN /n /m "Ваш выбор: "
if errorLevel 2 goto menu
set branch_name=
set /p branch_name="Введите название новой ветки: "
if "%branch_name%"=="" (
echo [!] Название ветки не может быть пустым!
pause
goto menu
)
git branch "%branch_name%"
echo.
echo [!] Ветка "%branch_name%" успешно создана! Вы остались в текущей ветке.
echo Чтобы перейти на нее выполните: git switch "%branch_name%"
pause
goto menu
Теперь в скрипте закрыты оба базовых сценария работы с ветками 💻
🔥 Сегодня разобрал крутую фичу в TypeScript оператор satisfies (появился в TS 4.9).
Раньше была частая проблема: если задаёшь объекту строгий тип (например, Record), то TypeScript забывает, где у тебя строка, а где массив. Из-за этого нельзя было просто так вызвать .toUpperCase() у строки без лишних проверок.
Оператор satisfies решает это идеально:
1. Он ПРОВЕРЯЕТ, что объект соответствует типу.
2. Но НЕ СУЖАЕТ автовыведенные типы полей!
Теперь TS точно знает, что palette.green это именно string, и спокойно даёт крутить с ним любые строковые методы.
Код и примеры закинул в конспекты, двигаемся дальше 🚀
Раньше была частая проблема: если задаёшь объекту строгий тип (например, Record), то TypeScript забывает, где у тебя строка, а где массив. Из-за этого нельзя было просто так вызвать .toUpperCase() у строки без лишних проверок.
Оператор satisfies решает это идеально:
1. Он ПРОВЕРЯЕТ, что объект соответствует типу.
2. Но НЕ СУЖАЕТ автовыведенные типы полей!
type Colors = "red" | "green" | "blue"
type RGB = [red: number, green: number, blue: number]
const palette = {
red: [255, 0, 0],
green: "#00ff00",
blue: [0, 0, 255],
} satisfies Record<Colors, string | RGB>
const greenNormalized = palette.green.toUpperCase()
Теперь TS точно знает, что palette.green это именно string, и спокойно даёт крутить с ним любые строковые методы.
Код и примеры закинул в конспекты, двигаемся дальше 🚀