Введение

Я уже более 7 лет активно использую TypeScript, применяя его в самых разных сценариях — от простых типизированных переменных до сложных условных типов и интерполяции. Однако TypeScript продолжает удивлять: сегодня я открыл для себя ещё один элегантный сценарий использования автовыведения типов в дженериках и функциях.

В этой статье разберём, как TypeScript автоматически выводит типы в дженериках на примере функции fetchFile из моего кода.


1. Что такое автовыведение типов?

Автовыведение типов (Type Inference) — это способность TypeScript автоматически определять типы данных без их явного указания.

Базовые примеры:

let age = 25;          // Вывод: `number`
const name = "Alice";  // Вывод: `string`

TypeScript понимает, что age — это number, а namestring.

Но что, если мы работаем с дженериками и функциями?


2. Автовыведение в дженериках и функциях

Рассмотрим мой пример с функцией fetchFile:

type FileContentFetcher<TParams> = (params: TParams) => CancelablePromise<TParams>;

export const fetchFile = <TParams>(getFileContent: FileContentFetcher<TParams>) => {
  return (requestParams: TParams) => {
    getFileContent(requestParams).then(downloadFile);
  };
};

Здесь TypeScript делает три ключевых вывода:

1. Автовыведение TParams на основе переданной функции

Когда мы вызываем:

fetchFile(API.findExcel)({ ... });

TypeScript:

  1. Смотрит на тип findExcel.

  2. Определяет, что его параметр имеет структуру:

    { requestBody: { docPkgVerEndDtFrom: string; docPkgVerEndDtTo: string } }
  3. Автоматически подставляет этот тип в TParams.

2. Проверка соответствия аргументов

Если передать неверные параметры:

fetchFile(API.Search.SearchApiService.findDocumentPackagesExcel1)({
  requestBody: {
    invalidField: "2025-05-05", // 🚫 Ошибка!
  },
});

TypeScript сразу укажет на ошибку, потому что invalidField не соответствует ожидаемому TParams.

3. Автовыведение возвращаемого типа

Функция fetchFile возвращает новую функцию, которая прини��ает TParams. TypeScript сохраняет связь типов на всех уровнях вложенности.


3. Почему это мощно?

  1. Минимум boilerplate-кода
    Не нужно явно указывать TParams — TypeScript выводит его автоматически.

  2. Безопасность типов
    Если API изменится (например, поле docPkgVerEndDtFrom переименуют), TypeScript сразу покажет ошибку в местах вызова.

  3. Гибкость
    Одна и та же функция fetchFile работает с любым API-методом, возвращающим Blob.


4. Где ещё полезно автовыведение в дженериках?

a) Утилиты для API

const createApiCall = <TResponse, TParams>(fetcher: (params: TParams) => TResponse) => {
  return (params: TParams) => fetcher(params);
};

const getUser = createApiCall(API.getUser); // TParams выводится из API.getUser

b) Обёртки для React-хуков

const useFetch = <TData>(url: string) => {
  const [data, setData] = useState<TData | null>(null);
  // ...
};

const { data } = useFetch("/api/users"); // TData выводится из возвращаемого значения API

5. Ограничения автовыведения

  1. Сложные дженерики
    Если тип слишком сложный, TypeScript может не вывести его автоматически — тогда нужно указывать явно:

    fetchFile<MyCustomParams>(someFetcher);
  2. Перегрузка функций
    Для перегруженных функций иногда нужно явно прописывать типы.


Вывод

Автовыведение типов в TypeScript — это мощный инструмент, который особенно полезен в дженериках и функциях. Мой пример с fetchFile показывает, как TypeScript автоматически связывает типы между переданной функцией и её аргументами, обеспечивая безопасность и удобство разработки.

Совет:

  • Используйте автовыведение везде, где можно.

  • Явно указывайте типы только в сложных случаях.

Теперь, когда вы знаете этот паттерн, попробуйте применить его в своих проектах! 🚀