История вопроса
С развитием TypeScript появилась необходимость автоматически извлекать тип возвращаемого значения из функции, особенно для больших проектов с множеством связанных между собой функций. Для этого был введён утилитарный тип ReturnType<T>, который появился в стандартной библиотеке начиная с версии TypeScript 2.8.
Проблема
В больших и сложных проектах бывает сложно поддерживать актуальность типов — если вручную указывать тип возвращаемого значения каждой функции и при этом произвести изменение сигнатур, легко получить рассогласованность, когда сигнатуры и реализации не совпадают. Дополнительно, если функция возвращает сложную структуру, не всегда легко вручную синхронизировать описание возвращаемого типа во всех местах использования.
Решение
Утилитарный тип ReturnType<T> автоматически извлекает возвращаемый тип функций и может использоваться для типизации результата вызова функции в любом месте кода. Это снижает количество ручной поддержки типовой инфраструктуры и минимизирует ошибки, связанные с несоответствием описанного и фактического типа возвращаемого значения.
Пример кода:
function createUser(name: string, age: number) { return { name, age, created: new Date() }; } type User = ReturnType<typeof createUser>; // User: { name: string; age: number; created: Date; }
Ключевые особенности:
Можно ли использовать ReturnType с методами классов?
Да, но важно помнить о контексте: если метод — это свойство объекта с функцией, используйте ReturnType<obj['метод']>.
Пример кода:
class MyClass { foo(x: number) { return x * 2; } } type FooReturn = ReturnType<MyClass['foo']>; // Type error! // Нужно так: type FooReturn = ReturnType<(x: number) => number>; // number // Или вынести метод как функцию: const obj = new MyClass(); type FooReturn2 = ReturnType<typeof obj.foo>;
Что вернет ReturnType для функций с void/never?
Для функции с объявленным типом void, ReturnType вернет void. Для never — never.
Пример кода:
function doNothing(): void {} type Result = ReturnType<typeof doNothing>; // void
Работает ли ReturnType с перегрузками функций?
Нет, ReturnType извлекает возвращаемый тип самой "реализации", а не всех перегрузок. Если перегрузок несколько — берется описанный тип реализации.
Пример кода:
function func(x: number): number; function func(x: string): string; function func(x: any): any { return x } type RT = ReturnType<typeof func>; // any
В проекте объявляют ручной тип для возвращаемого объекта функции. Функция меняется — тип не обновляется, вызовы падают в рантайме.
Плюсы:
Минусы:
Переходят на ReturnType везде, где используют значение, возвращаемое функцией. В случае изменений тип всегда актуален.
Плюсы:
Минусы: