#заметка дня
Что делать, если нужная вам библиотека не предоставила типы для всех публичных методов?
Ну вот такое вот архитектурное решение: метод экспортирован из модуля, а тип или интерфейс — нет?
Делать unknown или any? Копировать и переопределять с помощью as?
Ни в коем случае! Вам нуженпростой советский... ReturnType: https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype
Пример использования — на иллюстрации. Ну или ещё можно так:
#typescript #ts #types #бородач
Что делать, если нужная вам библиотека не предоставила типы для всех публичных методов?
Ну вот такое вот архитектурное решение: метод экспортирован из модуля, а тип или интерфейс — нет?
Делать unknown или any? Копировать и переопределять с помощью as?
Ни в коем случае! Вам нужен
Пример использования — на иллюстрации. Ну или ещё можно так:
const createPerson = () => ({
firstName: 'John',
lastName: 'Doe'
})
type Person = ReturnType<typeof createPerson>
Не делайте ерунды, котаны. Читайте документацию.#typescript #ts #types #бородач
#til дня
Вот есть у вас какая-то библиотека, которой можно передать некие обработчики событий. Особенно этим славятся карусели, кастомные селекты и прочие т. н. плагины.
Почему плагины? Потому что многие из них или до сих пор являются плагинами к jQuery, или буквально вырасли из них. Так уж повелось.
И вот эти самые обработчики событий получают доступ к
Куда нас пошлёт TypeScript с этим? Правильно, в «this implicitly has any type».
А что делать-то? Как указать тип this в методе?
Всё очень просто: начиная ещё с версии 2.0 для указания типа
И так же с любым конструктором объектов или функцией, принимающей коллбэки как аргумент.
Такой вот сумбурный TIL сегодня, да. Сразу можно увидеть, что у меня руки по локоть в легаси.
#typescript #бородач
Вот есть у вас какая-то библиотека, которой можно передать некие обработчики событий. Особенно этим славятся карусели, кастомные селекты и прочие т. н. плагины.
Почему плагины? Потому что многие из них или до сих пор являются плагинами к jQuery, или буквально вырасли из них. Так уж повелось.
И вот эти самые обработчики событий получают доступ к
this
, к инстансу объекта (функции, класса). Например, Selectize.js, покажем какой-то блок над селектом:
function onDropdownClose(value: string) {
this?.$input.parent().find(‘.alert’).html(value);
}
$(‘select’).selectize({
hideSelected: true,
openOnFocus: true,
onDropdownClose,
})
Куда нас пошлёт TypeScript с этим? Правильно, в «this implicitly has any type».
А что делать-то? Как указать тип this в методе?
Всё очень просто: начиная ещё с версии 2.0 для указания типа
this
его нужно передать как первый аргумент в функцию. Не бойтесь, остальные implicit аргументы оно не затрёт. Итого:
function onDropdownClose(this: SelectizeInstance, value: string)
И так же с любым конструктором объектов или функцией, принимающей коллбэки как аргумент.
Такой вот сумбурный TIL сегодня, да. Сразу можно увидеть, что у меня руки по локоть в легаси.
#typescript #бородач
#драма дня
Итак, сообщество опять бомбит. Вот вы спите, а там происходит ого-го какая драма!
Короче, TL;DR: Создатель Ruby on Rails, Давид Хейнемейер Ханссон (David Heinemeier Hansson) заявил, что TypeScript не нужен.
Подробнее: https://world.hey.com/dhh/turbo-8-is-dropping-typescript-70165c01
Суть ситуации в том, что (в основном в мире RoR) есть фреймворк Turbo. По факту, он успешно конкурирует с Astro, HTMX и прочими React Server Components и просит ещё. Бесшовная интеграция фронтенда с бакендом через передачу HTML различными способами: https://turbo.hotwired.dev/
Идея не нова, что-то похожее есть и в Drupal, и в October CMS, можно повторить и в Laravel и так далее.
Так вот Turbo до 7 версии включительно был написан на TypeScript, а сейчас Давид психанул. Из его сообщения можно сделать вывод, что ООП (а Turbo пишется в ООП-стиле) в современном JS вполне себе развилось до состояния, в котором с ним можно работать.
Но ещё явно прослеживается, что он просто устал воевать со сложными типами. Многим знакомо это ощущение, когда типы разрастаются до невероятных размеров и сложности, особенно когда схема передаваемых данных очень сложна.
Сообщество бурлит, ссылается на State of JS 2023, мол, 70% разработчиков использует TS. Проблема только в том, что не 70% разработчиков, а 70% поучаствовавших в опросе.
К слову, ситуация не нова. React как был на JS написан, так и остаётся. Правда, без громких заявлений.
Upd. там фейсбучный Flow, про который я забыл совсем. И определения TS-типов поставляются в отдельном пакете.
Ну и ещё лично я замечал, когда мне надо поэкспериментировать, я точно не выберу TS: в экспериментах типобезопасность это последнее, что меня волнует, а в рантайме тебя TS не особо спасает от дурацких решений (inb4 гигиена, тайпгарды и и контракты).
Интересно, скоро ли появится turbo.d.ts в пакете types? По-моему, Давид и определения поставлять не собирается. Что-то это уже ну такое 🙂
А как ваши дела с TS, котаны?
P. S. мне тут напомнили, что самая мякотка-то происходит в обсуждении PR с удалением TS: https://github.com/hotwired/turbo/pull/971
Там просто полыхают костры из ягодиц.
#typescript #javascript #ruby
Итак, сообщество опять бомбит. Вот вы спите, а там происходит ого-го какая драма!
Короче, TL;DR: Создатель Ruby on Rails, Давид Хейнемейер Ханссон (David Heinemeier Hansson) заявил, что TypeScript не нужен.
Подробнее: https://world.hey.com/dhh/turbo-8-is-dropping-typescript-70165c01
Суть ситуации в том, что (в основном в мире RoR) есть фреймворк Turbo. По факту, он успешно конкурирует с Astro, HTMX и прочими React Server Components и просит ещё. Бесшовная интеграция фронтенда с бакендом через передачу HTML различными способами: https://turbo.hotwired.dev/
Идея не нова, что-то похожее есть и в Drupal, и в October CMS, можно повторить и в Laravel и так далее.
Так вот Turbo до 7 версии включительно был написан на TypeScript, а сейчас Давид психанул. Из его сообщения можно сделать вывод, что ООП (а Turbo пишется в ООП-стиле) в современном JS вполне себе развилось до состояния, в котором с ним можно работать.
Но ещё явно прослеживается, что он просто устал воевать со сложными типами. Многим знакомо это ощущение, когда типы разрастаются до невероятных размеров и сложности, особенно когда схема передаваемых данных очень сложна.
Сообщество бурлит, ссылается на State of JS 2023, мол, 70% разработчиков использует TS. Проблема только в том, что не 70% разработчиков, а 70% поучаствовавших в опросе.
К слову, ситуация не нова. React как был на JS написан, так и остаётся. Правда, без громких заявлений.
Upd. там фейсбучный Flow, про который я забыл совсем. И определения TS-типов поставляются в отдельном пакете.
Ну и ещё лично я замечал, когда мне надо поэкспериментировать, я точно не выберу TS: в экспериментах типобезопасность это последнее, что меня волнует, а в рантайме тебя TS не особо спасает от дурацких решений (inb4 гигиена, тайпгарды и и контракты).
Интересно, скоро ли появится turbo.d.ts в пакете types? По-моему, Давид и определения поставлять не собирается. Что-то это уже ну такое 🙂
А как ваши дела с TS, котаны?
P. S. мне тут напомнили, что самая мякотка-то происходит в обсуждении PR с удалением TS: https://github.com/hotwired/turbo/pull/971
Там просто полыхают костры из ягодиц.
#typescript #javascript #ruby
#заметка дня
Как же у меня бомбит сейчас, вы бы знали. Но обо всём по порядку.
Кому-то из разработчиков JetBrains показалось полезным дать возможность скомпилировать все TypeScript файлы разом в JavaScript и положить их рядышком с оригиналами.
Да, я не шучу, одним кликом мышки можно скомпилировать вообще все TS-файлы в вашем проекте. При этом, компилятору абсолютно по барабану, смешанный у вас проект или нет. Ну и, заодно, на macOS ему ровно так же по барабану на регистр названий файлов.
И, естественно, класс Config.ts перезаписал собой файл конфигурации config.js 🫠
Хвала небу, в PhpStorm есть локальная история файла, потому что конфигурация, естественно, исключена из Git.
Моя жопа давно так не горела. Это ну вообще как? Зачем? Кому это может быть полезно?! Ну типа, должна же быть хоть какая-то веская причина так делать?
Я сейчас отдышусь и передам свои впечатления команде поддержки JetBrains, которые помогают нашей компании. Но не сразу, точно не сразу...
#typescript #jetbrains #надмозг
Как же у меня бомбит сейчас, вы бы знали. Но обо всём по порядку.
Кому-то из разработчиков JetBrains показалось полезным дать возможность скомпилировать все TypeScript файлы разом в JavaScript и положить их рядышком с оригиналами.
Да, я не шучу, одним кликом мышки можно скомпилировать вообще все TS-файлы в вашем проекте. При этом, компилятору абсолютно по барабану, смешанный у вас проект или нет. Ну и, заодно, на macOS ему ровно так же по барабану на регистр названий файлов.
И, естественно, класс Config.ts перезаписал собой файл конфигурации config.js 🫠
Хвала небу, в PhpStorm есть локальная история файла, потому что конфигурация, естественно, исключена из Git.
Моя жопа давно так не горела. Это ну вообще как? Зачем? Кому это может быть полезно?! Ну типа, должна же быть хоть какая-то веская причина так делать?
Я сейчас отдышусь и передам свои впечатления команде поддержки JetBrains, которые помогают нашей компании. Но не сразу, точно не сразу...
#typescript #jetbrains #надмозг
#заметка дня
Что делать, если нужная вам библиотека не предоставила типы для всех публичных методов?
Ну вот такое вот архитектурное решение: метод экспортирован из модуля, а тип или интерфейс — нет?
Делать unknown или any? Копировать и переопределять с помощью as?
Ни в коем случае! Вам нуженпростой советский... ReturnType: https://www.typescriptlang.org/docs/handbook/utility-types.html#returntypetype
Пример использования — на иллюстрации. Ну или ещё можно так:
#typescript #ts #types #бородач
Что делать, если нужная вам библиотека не предоставила типы для всех публичных методов?
Ну вот такое вот архитектурное решение: метод экспортирован из модуля, а тип или интерфейс — нет?
Делать unknown или any? Копировать и переопределять с помощью as?
Ни в коем случае! Вам нужен
Пример использования — на иллюстрации. Ну или ещё можно так:
const createPerson = () => ({
firstName: 'John',
lastName: 'Doe'
})
type Person = ReturnType<typeof createPerson>
Не делайте ерунды, котаны. Читайте документацию.#typescript #ts #types #бородач
#фишка дня
Кричащий банан 🍌 (да-да) принёс шикарную фишку TypeScript: как типизировать ключ объекта без каста.
Решение: заранее объявите тип переменной перебора как
Пруф на TS Playground.
#typescript #cast
Кричащий банан 🍌 (да-да) принёс шикарную фишку TypeScript: как типизировать ключ объекта без каста.
Решение: заранее объявите тип переменной перебора как
keyof typeof
. Всё, вы великолепны.Пруф на TS Playground.
#typescript #cast
#инструмент дня
Ладно, мы все можем согласиться, что у TypeScript замечательный офсайт, прекрасная документация и удобная песочница, но в мире есть сотни тысяч JS-библиотек и десятки тысяч из них либо написаны на TS, либо имеют выделенные типы.
А единой документации по этим типам нет!
Точнее, не было, но теперь вышел https://tsdocs.dev/
Это система поиска по существующим пакетам с типами. Она установит нужный пакет, распарсит типы и JSDoc и отобразит в удобном формате.
К слову, котаны, что вы предпочитаете по cmd- (ctrl)-click в редакторе? Прыгать к имплементации, или к типам?
Я вот — к имплементации, прыгать к типам меня раздражает.
#typescript #dts #types #doc
Ладно, мы все можем согласиться, что у TypeScript замечательный офсайт, прекрасная документация и удобная песочница, но в мире есть сотни тысяч JS-библиотек и десятки тысяч из них либо написаны на TS, либо имеют выделенные типы.
А единой документации по этим типам нет!
Точнее, не было, но теперь вышел https://tsdocs.dev/
Это система поиска по существующим пакетам с типами. Она установит нужный пакет, распарсит типы и JSDoc и отобразит в удобном формате.
К слову, котаны, что вы предпочитаете по cmd- (ctrl)-click в редакторе? Прыгать к имплементации, или к типам?
Я вот — к имплементации, прыгать к типам меня раздражает.
#typescript #dts #types #doc
#тип дня
Попробую вместо тега #фишка внести что-то новое для TypeScript. Пусть будет "тип", а там посмотрим.
И сегодня на повестке дня запрет определённых ключей при передаче объекта. Например, контекста в трекинге или тех же пропсов в React.
Как правило, контекст в трекинге передаётся в функцию-хелпер, а после — дополняется какими-то переменными среды. Как-то так:
Понятное дело, нам совсем неохота, чтобы кто-то случайно передал в контекст type, userId или env и затёр всё нафиг.
"Погоди, так разверни контекст повыше", — скажет кто-то умный.
Ну так тоже не стоит, мы не хотим сюрпризов уже на разбореполётов логов в случае инцидента, когда ожидалось одно, а на выходе — другое.
Проще сразу не дать сделать странное, как минимум на этапе введения контекста. Наш вариант в итоге стал таким:
Ну и конечно, ссылка на песочницу: пуньк.
Есть предложения получше, котаны? Ну кроме проверки в рантайме :)
#typescript #ts #type
Попробую вместо тега #фишка внести что-то новое для TypeScript. Пусть будет "тип", а там посмотрим.
И сегодня на повестке дня запрет определённых ключей при передаче объекта. Например, контекста в трекинге или тех же пропсов в React.
Как правило, контекст в трекинге передаётся в функцию-хелпер, а после — дополняется какими-то переменными среды. Как-то так:
function logEvent(severity: LogSeverity = "info", context: LogContext = {}) {
log(severity, {
type: "event",
userId: "rick@ro.ll",
env: "dev",
...context,
})
}
Понятное дело, нам совсем неохота, чтобы кто-то случайно передал в контекст type, userId или env и затёр всё нафиг.
"Погоди, так разверни контекст повыше", — скажет кто-то умный.
Ну так тоже не стоит, мы не хотим сюрпризов уже на разборе
Проще сразу не дать сделать странное, как минимум на этапе введения контекста. Наш вариант в итоге стал таким:
type LogContextDefaults = "type" | "userId" | "env";
type LogContext = {
[key: string]: string;
} & {
[key in LogContextDefaults]?: never;
}
Ну и конечно, ссылка на песочницу: пуньк.
Есть предложения получше, котаны? Ну кроме проверки в рантайме :)
#typescript #ts #type
#тип дня
Типом дня назначается вон тот в кожаной куртке. Да-да, о тебе говорю!
TL;DR: вычисленный тип функции с дженерик-аргументом можно сузить, декларируя тип как const.
Кроме шуток, разве тебя не бесит, что указываешь вот дженерик тип аргумента функции, производишь манипуляции над переданным объектом — а в ответ тебе вычисленный базовый тип?
Непонятно? Давай так:
Какой вычисленный тип получат first и second?
Очевидно, такой:
Но... это же довольно неудобно. А если мы схему валидируем, например? Или форму описываем. Или тесты пишем в конце-концов. Почему при заранее известном константном типе входных данных мы получаем вычисленную строку?
К счастью, начиная с TypeScript 5.0 можно объявлять дженерики как константные типы! Иначе говоря, работать с максимально узкими (narrow) типами. Это, собственно, аналог указания as const у предопределённой константы.
Использование простое:
И на выходе тип у first и second будет такой:
Песочница: пуньк.
Давайте исходя из полученной информации создадим валидатор по известной схеме данных и дальше поработаем с ним:
Определение getSurname приобретёт такой вид:
То есть, обратите внимание, не просто строку на вход, а конкретные, существующие в нужных параметрах строки.
Теперь это вполне себе напоминает удобную работу с коллекциями данных, не стыдно и форму провалидировать.
Песочница: пуньк.
Штука относительно новая, к ней ещё придётся немного привыкнуть. Но уже можно пробовать применять.
Ах да, ссылка на соответствующий PR в TypeScript: https://github.com/microsoft/TypeScript/pull/51865
#typescript #generic #const
Типом дня назначается вон тот в кожаной куртке. Да-да, о тебе говорю!
TL;DR: вычисленный тип функции с дженерик-аргументом можно сузить, декларируя тип как const.
Кроме шуток, разве тебя не бесит, что указываешь вот дженерик тип аргумента функции, производишь манипуляции над переданным объектом — а в ответ тебе вычисленный базовый тип?
Непонятно? Давай так:
function wrapNames <T>(names:T[]) {
return names.map<{name: T}>(name => ({name}));
}
const [first, second] = wrapNames(['Sergey', 'Alex'])
Какой вычисленный тип получат first и second?
Очевидно, такой:
{
name: string;
}
Но... это же довольно неудобно. А если мы схему валидируем, например? Или форму описываем. Или тесты пишем в конце-концов. Почему при заранее известном константном типе входных данных мы получаем вычисленную строку?
К счастью, начиная с TypeScript 5.0 можно объявлять дженерики как константные типы! Иначе говоря, работать с максимально узкими (narrow) типами. Это, собственно, аналог указания as const у предопределённой константы.
Использование простое:
function wrapNames <const T>(names:T[])
И на выходе тип у first и second будет такой:
{
name: "Sergey" | "Alex";
}
Песочница: пуньк.
Давайте исходя из полученной информации создадим валидатор по известной схеме данных и дальше поработаем с ним:
// initValidator
function parse<const T extends { name: string; surname: string }>(users: T[]) {
return (name: T['name']) => users.find(u => u.name === name)?.surname;
}
// validate
const getSurname = parse([
{
name: 'Joe',
surname: 'Doe',
age: 30,
},
{
name: 'John',
surname: 'Dohn'
}
]);
Определение getSurname приобретёт такой вид:
getSurname: (name: "Joe" | "John") => string | undefined
То есть, обратите внимание, не просто строку на вход, а конкретные, существующие в нужных параметрах строки.
Теперь это вполне себе напоминает удобную работу с коллекциями данных, не стыдно и форму провалидировать.
Песочница: пуньк.
Штука относительно новая, к ней ещё придётся немного привыкнуть. Но уже можно пробовать применять.
Ах да, ссылка на соответствующий PR в TypeScript: https://github.com/microsoft/TypeScript/pull/51865
#typescript #generic #const
GitHub
`const` modifier on type parameters by ahejlsberg · Pull Request #51865 · microsoft/TypeScript
With this PR we implement a new const modifier for type parameters. In a function, method, or constructor invocation, when a literal expression in an argument is contextually typed by a const type ...
#тип дня
Кричащий банан 🍌 (да-да) принёс шикарную фишку TypeScript: как типизировать ключ объекта без каста.
Решение: заранее объявите тип переменной перебора как
Пруф на TS Playground.
#typescript #cast #бородач
Кричащий банан 🍌 (да-да) принёс шикарную фишку TypeScript: как типизировать ключ объекта без каста.
Решение: заранее объявите тип переменной перебора как
keyof typeof
. Всё, вы великолепны.Пруф на TS Playground.
#typescript #cast #бородач