Пейджер

🌍 Вітаю вас, шаноўныя сябры! 🇧🇾

TL;DR
  • NoInfer — утилитарный тип из TypeScript 5.4
  • Блокирует автоматический вывод типа из аргумента
  • В mergeConfigs предотвращает расширение типа пользователем
  • NoInfer с never делает дженерик обязательным для указания
🌍 Вітаю вас, шаноўныя сябры! 🇧🇾

Ребятки давненько не было технических постов, последнее время, по определенным причинам, стало меньше времени, но они есть и будут 💪, у меня скопилась уже целая кучка идей о чем я хотел бы написать.

Недавно я уже анонсировал этот пост, пришло время вскрываться, но не вдоль 😰.
Поговорим про NoInfer, будет интересно, не все знают что это и для чего, к слову данный утилитарный тип был зарелизин в версии 5.4 ⚙️.

🚀 Мотивация

Бывают случаи, когда нужно:

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

На помощь приходит NoInfer 💪.

Звучит классно, но сложно, давайте разбираться, возможно это знание поможет вам уже завтра решить то, что не решалось вчера 🔥.

✔️ Вводная часть

Так-с, что нужно понимать?

💡 Во-первых, noInfer — это про generics, если не знаете как они работают вам сюды, поста про это пока нет, но я думаю в будущем обязательно сделаю.

💡 Во-вторых, в TypeScript есть Infer keyword, который используется в conditional types, и чтобы вы случайно не надумали, — это не противоположность к noInfer. Кстати про infer постик то у меня есть для вас 😏.

✔️ Основа

Классическое поведение функции c generic:

function identity<T>(arg: T): T {
  return arg;
}

const identityResult1 = identity<number>(3) // number
const identityResult1 = 
identity<number>("строка") // 'string' is not type 'number'

const identityResult3 = identity(1) // 1


Если в generic передать тип, то будет использован именно он,
а если тип не указать — TypeScript попробует вывести его сам из аргумента.

Ну вроде бы все понятно, окей, двигаем дальше 👇

✔️ Двигаем дальше:

А что будет если обернуть тип аргумента в noInfer ?

function identityNoInfer<T>(arg: NoInfer<T>): T {
  return arg;
}

const identityNoInfer1 = identityNoInfer(123) // unknown
const identityNoInfer2 = identityNoInfer<number>(123) // number


Что мы наблюдаем 👀NoInfer не позволяет значению быть источником вывода для T.
Таким образом, результат выводится как unknown.
Нам необходимо явно указать тип для identityNoInfer, чтобы получить желаемый тип возвращаемого значения.

Наверное вы все еще думаете, ну и чего? и зачем мне это? 🤷‍♀️

✔️ Покажу вам 2 интересных примера

1️⃣ Бывают случаи, когда у нас есть необходимость сделать merge дефолтных и пользовательских настроек.

Допустим, есть функция mergeConfigs:

function mergeConfigs<T>(defaults: T, user: T) {
  return { ...defaults, ...user };
}


Как будто бы все четко, получаем агрегированные данные, НО к сожалению есть тут лазейка для ошибок, TS такое скушает и ничего не скажет ☹️:

const config = mergeConfigs(
  { theme: "light", debug: false },
  { debug: true, logLevel: "verbose" } 
)


Что произошло? Расширился тип, добавилось новое поле logLevel, которого в дефолтах не было! В результате мы получаем валидный код, но в рантайме может возникнуть проблема ⚠️

🔧 Исправляем:

function mergeConfigs<T>(defaults: T, user: NoInfer<T>) {
  return { ...defaults, ...user };
}


В таком варианте, за счет NoInfer мы предотвращаем расширение типа, и тип формируется только на основании аргумента defaults.
Если передать данные как выше, TS выдаст ошибку. Все примеры описаны в TS песочнице.

2️⃣ Порой хочется сделать так, чтобы передача типа в generic была обязательным действием, и тут к нам на помощь снова приходит noInfer:

function makeRequest<T = never>(url: string, body: NoInfer<T>) {
  console.log("POST", url, body);
}

// ❌ Ошибка: TypeScript не может вывести T
makeRequest("/users", { name: "Ilya" });

// ✅ Работает только если указать тип вручную
makeRequest<{ name: string }>("/users", { name: "Ilya" });


Комбинация NoInfer + never делает дженерик обязательным для указания.
В примере body становится типом never, а мы туда пихаем { name: string; } — на выходе ошибка 🔞

💬 Делитесь своим мнением в комментариях👇! Если вам понравился пост, не забудьте поставить лайк! 👍

#TYPESCRIPT
Медиа 1
Хотите больше таких постов?
Подпишитесь на канал и читайте продолжение в Telegram.
Подписаться на @ivanchikovitclub Открыть пост в Telegram