Видеоуроки, интерактивный редактор и сохранение прогресса — бесплатно, сразу после входа.
ВойтиСоздать аккаунт — бесплатноЗакончили урок?
Войдите, чтобы отмечать прогресс
T выводится из типа загрузчика: async () => ({ id: 1 }) имеет тип () => Promise<{ id: number }>, значит T = { id: number }. Результат Promise<{ id: number }>, и в .then приходит объект с id. Сам userId при этом Promise<number>.
Обрати внимание, что T здесь описывает данные, а не промис. Если написать withRetry<T>(loader: () => T): T, то T выведется как Promise<{ id: number }>. Это тоже будет работать, но такая сигнатура примет и синхронную функцию, для которой await и повтор не имеют смысла. Явный Promise<T> в аргументе документирует, что ждём именно асинхронный загрузчик.
Если тип промиса уже есть, а нужен тип его значения, есть встроенная утилита:
Awaited разворачивает промисы рекурсивно, так же как это делает await в рантайме. Удобно в паре с ReturnType: Awaited<ReturnType<typeof loadUser>> даёт тип того, что вернёт асинхронная функция после await.
Этот приём лежит в основе типизации любых обёрток над запросами: retry, таймауты, кеш, индикаторы загрузки. Если обёртка объявлена через unknown или any, все типы ответа сервера теряются на первом же слое.