Пейджер

Погнали дальше про DOOM на TS типах

TL;DR
  • infer выводит новый тип из переданного, работает только с extends
  • Пример: `Icon${infer Name}` убирает префикс Icon из названий
  • Степени двойки заранее записаны в массив — вместо вычисления на лету
  • Такой подход ускоряет расчёты и экономит ресурсы
Погнали дальше про DOOM на TS типах

Хочу немного разжевать трюк с infer, так как это довольно непонятная концепция в языке в принципе. Че он дает? Возможность выделить новый тип из переданного. Использовали когда нибудь ReturnType? Вот как выглядит его реализация
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
По-русски это можно прочитать как "если переданный тип Т это функция ((...args: []) =>), то то что она вернет обзови как R и верни; иначе хз"
То есть мы не знали что за тип вернет Т, но сказали его вытащить как новую "переменную"
Тут оговорочка, infer можно использовать только совместно с extends
Собственно, это открывает нам путь к условным выражениям, которые, совместно с концепцией сужения типов позволяют на типах написать хоть тудушку, хоть дум

Еще одна прикольная штука с infer. Представьте что у вас есть куча каких то иконок, названия которых начинаются с Icon - IconArrowUp, IconWallet и т.д. Вы хотите определить тип для этой иконки, но не хотите все писать с префиксом. Что приходит на ум? iconName.slice(4)? Зацените как это можно на чистом ts сделать
type WithoutIconPrefix<IconName> = IconName extends `Icon${infer Name}`
    ? Name
    : IconName;

type Wallet = WithoutIconPrefix<"IconWallet">; // "Wallet"

В нашем думе это используют чтобы реверснуть строку, например

И еще одна вещь которую хотел бы оттуда подсветить, это предрасчет значений. Почему то в современной разработке об этом забыли и считают все на лету. Но раньше, особенно в условиях ограниченных ресурсов, такое часто использовали.
Так вот. Представьте что вам нужно по заданному параметру что то посчитать. Например, взять степень двойки. Скорее всего, вы в лоб возведете 2 в степень и в большинстве случаев будете правы. Но! Если у вас слишком мало ресурсов или, как здесь, нет умножения, что тогда?
Так как результаты возведения двойки в степень никогда не изменятся, то есть 2^3 всегда будет 8, то мы можем заранее определить набор результатов и просто брать из них как из Map

type PowersOfTwo = [
  /* 2**0  */ 1,
  /* 2**1  */ 2,
  /* 2**2  */ 4,
  /* 2**3  */ 8,
//  ...
  /* 2**30 */ 1073741824,
  /* 2**31 */ 2147483648,
];

Ну а дальшу мы просто type CubeOfTwo = PowersOfTwo[3]; // 8. Круто же?

Дальше я этот проект разбирать не вижу смысла, уж больно душные штуки там присутствуют. Но делитесь в комментах или шлите в личку если найдете что то клевое!
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @coaled_frontender Открыть пост в Telegram