Использовал ли generic вместе с infer в TypeScript?

Ответ

Да, использовал. В TypeScript infer внутри условных типов позволяет вывести тип из другого типа, что особенно полезно при создании утилитарных типов для работы с промисами, функциями или структурами данных в Node.js.

Пример извлечения типа из Promise:

type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type StringResult = UnwrapPromise<Promise<string>>; // string
type NumberResult = UnwrapPromise<number>; // number

Практическое применение в Node.js: Часто использую это для типизации результатов асинхронных операций, например, при работе с async/await или библиотеками вроде Prisma:

type ExtractQueryResult<T> = T extends (...args: any[]) => Promise<infer U> ? U : never;

// Для функции, возвращающей промис с пользователем
type User = ExtractQueryResult<typeof getUserById>;

infer также лежит в основе встроенных утилит TypeScript, таких как ReturnType и Parameters, которые я применяю для улучшения типизации в Express-роутах или сервисных слоях.

Ответ 18+ 🔞

А, ну ты про этот infer! Да, конечно, использовал, куда ж без него. Это ж, бля, один из главных инструментов, когда начинаешь ковыряться в типах поглубже, а не просто string да number писать. Без него как без рук, честно говоря.

Вот смотри, как из промиса тип вытащить:

type UnwrapPromise<T> = T extends Promise<infer U> ? U : T;

type StringResult = UnwrapPromise<Promise<string>>; // string
type NumberResult = UnwrapPromise<number>; // number

Суть в чём? infer U — это как волшебное слово. Ты говоришь TypeScript: «Слушай, а вот если T у нас промис, то вытащи-ка мне, что у него внутри, в этот U, а я потом с этим U поработаю». И он такой: «Ага, понял!» И вытаскивает. Если не промис — ну, хуй с ним, оставляем как есть. Просто и гениально, ёпта.

А на практике где это влетает? Да везде, где асинхронщина! Особенно в Node.js, когда работаешь с какими-нибудь ORM вроде Prisma или просто со своими функциями-запросчиками.

type ExtractQueryResult<T> = T extends (...args: any[]) => Promise<infer U> ? U : never;

// Допустим, есть функция, которая лезет в базу за пользователем
type User = ExtractQueryResult<typeof getUserById>;

Вот смотри: ты написал функцию getUserById. Она возвращает Promise<{id: number, name: string}>. А тебе в другом месте нужен именно тип этого пользователя, без промиса. Заворачивать всё в Awaited? Можно, конечно. А можно вот так, своим типом. Подставляешь функцию — и на тебе, готовый тип объекта. Удобно до безобразия, ядрёна вошь!

И самое главное — ты, наверное, даже не задумывался, но все эти встроенные штуки вроде ReturnType или Parameters — они внутри на том же infer и работают! TypeScript сам себе такими утилитами пользуется. А мы их потом в Express-роутах применяем, чтобы не описывать типы ответов и параметров вручную, как последние распиздяи. В общем, вещь, без которой типизация — это просто пизда рулю, а не типизация.