Прокачиваю свои 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, и спокойно даёт крутить с ним любые строковые методы.
Код и примеры закинул в конспекты, двигаемся дальше 🚀
Разбор задачи: пишем свой
Встроенный тип
Пишем свой рекурсивный тип!
Что тут происходит и какие фишки TS задействованы:
1) Mapped Types (
2) Conditional Types (
3) Record - безопасная проверка на объектную структуру (в отличие от
4) Recursive Types (
💻 Пример использования:
DeepPartial в TypeScript 🧠Встроенный тип
Partial делает необязательными только ключи верхнего уровня. А что делать, если у нас сложная вложенная структура и мы хотим сделать optional абсолютно все поля на всех уровнях вложенности?Пишем свой рекурсивный тип!
type DeepPartial<T> = {
[key in keyof T]?: T[key] extends Record<string, unknown>
? DeepPartial<T[key]>
: T[key]
}Что тут происходит и какие фишки TS задействованы:
1) Mapped Types (
[key in keyof T]?: ...) - проходим по всем ключам объекта и делаем их необязательными с помощью ?.2) Conditional Types (
T[key] extends ... ? A : B) - проверяем, является ли значение вложенным объектом.3) Record - безопасная проверка на объектную структуру (в отличие от
any).4) Recursive Types (
DeepPartial) - если внутри объект, вызываем DeepPartial снова для вложенного типа.💻 Пример использования:
type User = {
name: string;
details: {
age: number;
address: {
city: string;
};
};
};
// Теперь ВСЕ поля на любом уровне вложенности стали необязательными!
type PartialUser = DeepPartial;
const user1: PartialUser = {}; // Валидно
const user2: PartialUser = {
details: {
address: {
city: "Москва", // Не обязательно передавать name или age
},
},
};Автоматизирую Git: утилита для слияния веток ⚙️
Решил упростить себе жизнь и написать тулзу (
Что уже работает:
1. Автоматическое определение текущей ветки.
2. Проверка изменений в проекте через
Что в планах:
Добавить автоматический пуш фичи, быстрый перенос изменений в
Маленькими шагами собираем полезную автоматизацию 💻✨
Решил упростить себе жизнь и написать тулзу (
merger_branch.bat), которая берет на себя рутину при работе с feature-ветками.Что уже работает:
1. Автоматическое определение текущей ветки.
2. Проверка изменений в проекте через
git status --porcelain.Что в планах:
Добавить автоматический пуш фичи, быстрый перенос изменений в
main и забор обновления с GitHub.Маленькими шагами собираем полезную автоматизацию 💻✨
🔥1
Помните шаблон скрипта, который я выкладывал пару дней назад?
Написал для него полноценную логику! Теперь вся рутина с ветками автоматизирована:
Осталось добавить пару мелких фишек, и будет идеальная утилита для ежедневной работы!
Написал для него полноценную логику! Теперь вся рутина с ветками автоматизирована:
add ➔ commit ➔ push feature ➔ checkout main ➔ pull ➔ merge ➔ push main.Осталось добавить пару мелких фишек, и будет идеальная утилита для ежедневной работы!
Media is too big
VIEW IN TELEGRAM
Полностью доделал письмо на MJML! ✉️
Сверстал его всего за пару часов. Итоговый HTML-файл получился на 1500+ строк кода, хотя исходник на MJML занял всего около 160 строк. Вот так фреймворк реально облегчает работу с адаптивной версткой писем! 🚀
Сверстал его всего за пару часов. Итоговый HTML-файл получился на 1500+ строк кода, хотя исходник на MJML занял всего около 160 строк. Вот так фреймворк реально облегчает работу с адаптивной версткой писем! 🚀
❤2
Начинается самое интересное в TypeScript:
Переходим к
// .ts, .dts -> skipLibCheck
// Где писать типы? .ts / dts
// import из dts без импорта
// dts за пределами src -> includes
// reference type, reference path
// npm lodash (посмотреть кол-во js'ов) .dts, vite .ts (@types)
// lodash внутри и как там устроен reference
// что такое declare
// Как типизировать window
// declare module 'libname'
// "paths": { "some-library": ["./src/two.ts"] },
// типизация картинок(svg/png/jpg), css
Переходим к
.d.ts, declare и модулям!Сегодня наконец-то до конца понял, зачем нужны декларативные файлы (
Раньше эта тема казалась какой-то абстрактной теорией, но сегодня наткнулся на шикарный пример с проверкой на исчерпываемость (
В чем суть:
1) Объявляем сигнатуру функции
2) Теперь TS во время разработки нативно подхватывает её и сужает типы! Если я забыл обработать какой-то из статусов в
3) При этом сама инструкция работает только как страховка на этапе компиляции и исчезает в итоговом JS.
Очень крутое ощущение, когда непонятная концепция превращается в логичный и понятный инструмент. Буду изучать дальше, чтобы еще лучше разбираться в конфигах и продвинутой типизации!
.d.ts) в TypeScript! 💡Раньше эта тема казалась какой-то абстрактной теорией, но сегодня наткнулся на шикарный пример с проверкой на исчерпываемость (
assertExhaustiveness).В чем суть:
1) Объявляем сигнатуру функции
function assertExhaustiveness(value: never): never в .d.ts файле.2) Теперь TS во время разработки нативно подхватывает её и сужает типы! Если я забыл обработать какой-то из статусов в
if, TypeScript сразу подсветит ошибку и не даст собрать проект.3) При этом сама инструкция работает только как страховка на этапе компиляции и исчезает в итоговом JS.
Очень крутое ощущение, когда непонятная концепция превращается в логичный и понятный инструмент. Буду изучать дальше, чтобы еще лучше разбираться в конфигах и продвинутой типизации!
❤1