Будни разработчика
14.6K subscribers
1.14K photos
319 videos
7 files
1.96K links
Блог Lead JS-разработчика из Хельсинки
Автор: @bekharsky

По рекламе: https://telega.in/channels/htmlshit/card?r=GLOiHluU или https://t.me/it_adv

Чат: https://t.me/htmlshitchat

№5001017849, https://www.gosuslugi.ru/snet/679b74f8dad2d930d2eaa978
Download Telegram
#тип дня

Говоришь такой коллеге: «Ты зачем столько классов насоздавал для такой простой вещи? Используй CSS-переменные».

А он приходит к тебе с картинкой выше и грустный весь.

Что мы делаем в таком случае?

Да очень просто, дополняем интерфейс CSSProperties, чтобы до реакта, наконец, дошло:


declare module 'react' {
interface CSSProperties {
[key: `--${string}`]: string | number
}
}


Пруф: песочница.

Странно, конечно, что это не из коробки всё.

#css #types #react #typescript
#тип дня

Вышел TypeScript 5.4.

А это что значит? Что у нас теперь есть служебный тип NoInfer.

Коротко, зачем он нужен: с его указанием TS больше не будет пытаться угадать тип передаваемого аргумента. Например, если не указать тип массива ["red", "yellow", "green"], TS определит его как string[] и разрешит запихнуть туда значение "blue" или, что хуже, позволить вашему коду попытаться, например, это самое значение в нём найти:


function createStreetLight<C extends string>(colors: C[], defaultColor?: C) {
// ...
}

createStreetLight(["red", "yellow", "green"], "blue");


Чтобы такого не происходило, есть два пути. Первый:

function createStreetLight<C extends string, D extends C>(colors: C[], defaultColor?: D) {
}

createStreetLight(["red", "yellow", "green"], "blue");
// ~~~~~~
// error!
// Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.


Ну такое, многословно и D больше нигде в коде не используется. Вот тут и приходит на помощь NoInfer:

function createStreetLight<C extends string>(colors: C[], defaultColor?: NoInfer<C>) {
// ...
}

createStreetLight(["red", "yellow", "green"], "blue");
// ~~~~~~
// error!
// Argument of type '"blue"' is not assignable to parameter of type '"red" | "yellow" | "green" | undefined'.


Всё, тип массива определён как, практически, у константы ["red", "yellow", "green"] и передать "blue" уже не выйдет.

Естественно, улучшений и нововведений в TS 5.4 сильно больше, рекомендую прочитать заметки о выпуске: https://devblogs.microsoft.com/typescript/announcing-typescript-5-4/

#typescript #generics
#ссылка дня

Типизирование React-компонентов, рефов и хуков может обернуться большой болью. Особенно если в первый раз. Но к счастью, у нас есть GitHub, который добрые люди используют не только как хранилище кода, но и как идеальный универсальный блог :)

Встречайте: https://github.com/typescript-cheatsheets/react

Буквально, из описания: «Cheatsheets for experienced React developers getting started with TypeScript».

Впрочем, у ребят есть и более привычная веб-версия, разбитая на секции: https://react-typescript-cheatsheet.netlify.app/

Мне, например, недавно понадобилось сделать полиморфичный компонент, который в зависимости от условий мог становиться то ссылкой, то кнопкой (какой прекрасный повод для холивара). Я не нашёл решения непосредственно здесь, зато нашёл в обсуждениях и PR. Что тоже показывает, как удобен GitHub для коллективного блога.

В общем, всем типов, котаны.

#typescript #react #бородач
#библиотека дня

— А что, если типы надо проверять в рантайме?
— Да не, херня какая-то...


Впрочем, создателям библиотеки Typia так совсем не кажется. Да и вам, в целом, казаться не должно: TypeScript, конечно, большой молодец, но типы проверяет только на этапе компиляции. И, конечно же, мы все верим в святые контракты :)

Библиотека предлагает не только проверку входящих данных, но и соответствие JSON описанию.

Есть как простые is и equals, возвращающие логическое соответствие, так и assert и assertEquals, кидающие ошибку.

Отличие is от equals в том, что is менее строгий и позволяет расширение объекта свойствами, которых нет в интерфейсе. Но описанные при этом должны соответствовать.

const input: unknown = {
id: v4(),
email: "samchon.github@gmail.com",
age: 30,
extra: "superfluous property", // extra
};

const is: boolean = typia.is<IMember>(input);const
equals: boolean = typia.equals<IMember>(input);

console.log(is, equals); // true, false


Обратили внимание? Схема не нужна!

Как-то так. Кто использовал уже?

#typescript #types
#инструмент дня

Если меня спросят, на чем я стал бы делать ранний прототип, я бы ответил Drupal. Ну или Ruby on Rails. Ну просто потому что я их знаю. На Drupal вообще мышкой можно все накликать и получить рабочий API.

Но, конечно, это уже сравнительно оторвано от реальности :) Простой CRUD aka Create-Read-Update-Delete можно собрать тысячей разных способов.

Так что стоит принести ещё один: Remult.

https://remult.dev/

Remult использует всю мощь декораторов TypeScript для описания своих т. н. сущностей, которые потом станут моделями.

import { Entity, Fields } from "remult"

@Entity("tasks", {
allowApiCrud: true
})
export class Task {
@Fields.cuid()
id = ""

@Fields.string()
title = ""

@Fields.boolean()
completed = false

@Fields.createdAt()
createdAt?: Date
}


После чего остается только зарегистрировать созданную сущность в сервере на, например, express и получить готовый CRUD API.

Останется дело за фронтендом, который автоматом тут не генерируется, зато вам доступно множество хелперов для управления своими сущностями.

Прекрасная документация, отличные пошаговые инструкции к разным фреймворкам. Ребята однозначно старались.

Горячая рекомендация, в целом.

#typescript #crud
#инструмент дня

Ладно, мы все можем согласиться, что у TypeScript замечательный офсайт, прекрасная документация и удобная песочница, но в мире есть сотни тысяч JS-библиотек и десятки тысяч из них либо написаны на TS, либо имеют выделенные типы.

А единой документации по этим типам нет!

Точнее, не было, но теперь вышел https://tsdocs.dev/

Это система поиска по существующим пакетам с типами. Она установит нужный пакет, распарсит типы и JSDoc и отобразит в удобном формате.

К слову, котаны, что вы предпочитаете по cmd- (ctrl)-click в редакторе? Прыгать к имплементации, или к типам?

Я вот — к имплементации, прыгать к типам меня раздражает.

#typescript #dts #types #doc #бородач
#тип дня

Что делать если вам нужно создать тип, параметры которого служат для передачи в библиотечную функцию? Aka тип аргументов не торчит наружу?

Не делайте это ручками, используйте служебный тип Parameters!


const createPerson = ({
firstName,
lastName
}: {
firstName: string,
lastName: string
}) => ({
firstName,
lastName
})

type CreatePersonParams = Parameters<typeof createPerson>[0];

const params: CreatePersonParams = {
firstName: 'John',
lastName: 'Doe'
};


Песочница

#typescript #utility
#тип дня

Четыре ночи провёл в деревне в глубинной Финляндии и возвращаться в привычный режим очень и очень тяжело.

Прыжки со скалы просто так не проходят.

Здесь отмечают день солнцестояния. Официальный выходной, плюс многие компании добавляют ещё один день — канун. Из города уезжают вообще все, пустота.

В общем, тип дня от Кори Хауса: как указать TypeScript, что поле принимает любое строковое значение, но при этом получить автоподсказку для наиболее часто используемых из них?

Очень просто:

type Status = 'open' | 'closed' | string & {}


Результат на иллюстрации. Песочница.

Объединение с пустым типом предотвращает попытки языкового сервера от приведения типа к строке.

На самом деле это равнозначно следующему выражению, более понятному:

type Status = 'open' | 'closed' | Omit<string, "open" | "closed">


Пользуемся!

#typescript
#новость дня

В node.js появилась экспериментальная нативная поддержка TypeScript!

Крепко же их bun приложил...

Ссылка на PR: https://github.com/nodejs/node/pull/53725

По факту происходит отбрасывание типов, поэтому средства вроде Enum и namespace не поддерживаются. Инициатива предоставления стабильного API поверх TypeScript получила название amaro и в дальнейшем планируется выделение в отдельный обновляемый модуль. Работает (кто бы сомневался) при помощи swc, собранного в WebAssembly!

Так что никаких больше ts-node!

node main.ts

...и поехали!

#node #typescript #ts
#расширение дня

Дал слабину и где-то в глубине кода указал any?

Воспользовался DefinitelyTyped, не проверив?

И при этом не используешь WebStorm?

Есть решение! Расширение для VS Code any-xray от Дана Вандеркама: https://marketplace.visualstudio.com/items?itemName=danvk.any-xray

Про DefinitelyTyped не шутка, всякое бывает: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b0ad06b09bd5547cf6f01a8355cbcb309d3f5e24/types/find-package-json/package-json.d.ts#L449

У React в типах, кстати, тоже.

Это не плохо само по себе, не все хотят заниматься ментальной гимнастикой там, где в целом можно спихнуть проверки на пользователя типов.

Но подсветить такие случаи, чтобы не попасть впросак — удобно.

#vscode #typescript
#инструмент дня

Устал вручную типизировать ответы от API для TypeScript или любого другого типизированного языка?

Есть решение!

https://app.quicktype.io/

Фиганул туда JSON — получил нужную структуру или описание типа, даже с тайпгардами. Уютненько!

Есть расширение для VS Code: https://marketplace.visualstudio.com/items?itemName=quicktype.quicktype

Ещё один мощный инструмент в тему дня: https://transform.tools. Одним типизированием JSON не ограничивается: можно CSS в Tailwind, а можно Flow в TypeScript.

Вот, например, если кто использует Zod — конвертор типов в схему Zod: https://transform.tools/typescript-to-zod

#json #typescript #type #бородач
Media is too big
VIEW IN TELEGRAM
#новость дня

Вчерашнего дня, конечно, и многие из вас уже в курсе, но...

TypeScript переписывают на Go!

Да, если вы не знали — транслятор TypeScript всё это время был написан на самом себе, что, как вы понимаете, не делало его быстрым :)

И вот, новость: https://devblogs.microsoft.com/typescript/typescript-native-port/

Результат ошеломляет: разбор типов и сборка уже в 10 раз быстрее! Это означает, что и LSP в ваших IDE будут быстрее. И работать станет приятнее.

Очень рекомендую пойти почитать статью.

Кстати, кто же этот седой дядя на видео? А это Андерс Хейлсберг! Создатель Turbo Pascal, Delphi, C# и, внезапно, TypeScript.

И на этом видео он, в том числе, объясняет, почему не Rust. Этим вопросом задолбали уже всю команду.

И, если коротко:
1. Это портирование, а не переписывание. Они хотели оставить структуру проекта и работы над ним той же, что и была.
2. Rust, хоть и облегчает управление памятью, полностью не освобождает от связанного с этим управлением бойлерплейта. И, поскольку, структура транслятора TypeScript представляет из собой огромный набор вложенных друг в друга структур, количество бойлерплейта вышло бы неразумным.

В общем, нас ждёт дивный новый мир! И я очень рад. И выбором языка тоже.

#typescript #go
#баг дня

Как вы думаете, что обозначает тип {}?

Ну, буквально:


type b = {};


Быть может, пустой объект? Да. А может, объект с любыми свойствами? Тоже да. А может, число или строка? И опять, да. А пустые? Да! А может, булево значение? Невероятно, но тоже да!

А может, null или undefined ? Нет. Вот тут — нет. Песочница.

Поэтому смысла в использовании типов {} или Object (второе лишь псевдоним к первому) довольно мало.

Если вам нужен пустой объект — так и пишите, Record<PropertyKey, never>.

Подробнее у Мэтта Покока: https://www.totaltypescript.com/the-empty-object-type-in-typescript.

В чём же баг, спросите вы?

А баг у нас на этот раз в реализации проверки типов в WebStorm/PhpStorm. У JetBrains, короче.

Мы выводим типы из схем Zod, но для целей создания шаблона, мне потребовалось исключить некоторые свойства из проверки:


TemplateQueryDetails = Omit<
z.infer<typeof QueryDetails>, 'metadata'
>;


И мощно получил в лицо: тип ресолвился за 3 минуты на MacBook Pro M2, вешая интерфейс PhpStorm напрочь. Каждый раз.

Решение пришло откуда не ждали:


TemplateQueryDetails = Omit<
z.infer<typeof QueryDetails>, 'metadata'
> & {};


Обратите внимание на пустой тип. Обнаружил я это случайно: в первом варианте я ещё и добавлял айди шаблона, но впоследствии — отказался.

По всей видимости, система типов IntelliJ построена таким способом, что рассчитвывает конъюнкцию типов как новый тип и кеширует на месте. Но это лишь предположение.

В VS Code, кстати, проблемы не наблюдается.

После обращения в поддержку, мне было рекомендовано включить настройку Use types from server, что буквально выключает встроенные средства и использует типы от LSP. Что, собственно, мне только в плюс.

А как ваши дни проходят? 🙂

#jetbrains #typescript #lsp