Получение типа возврата функции

У меня есть следующая функция:

function test(): number {
    return 42;
}

Я могу получить тип функции при помощи typeof:

type t = typeof test;

Здесь, t будет () => number.

Существует ли способ получить тип возврата функции? Я хотел бы t быть number вместо () => number.

62
задан 15 March 2016 в 19:47

8 ответов

РЕДАКТИРОВАНИЕ

С TypeScript 2.8 это официально возможно с ReturnType<T>.

type T10 = ReturnType<() => string>;  // string
type T11 = ReturnType<(s: string) => void>;  // void
type T12 = ReturnType<(<T>() => T)>;  // {}
type T13 = ReturnType<(<T extends U, U extends number[]>() => T)>;  // number[]

См. здесь для деталей.

TypeScript является потрясающим!

<час>

Олдскульный взлом

ответ Ryan больше не работает, к сожалению. Но я изменил его со взломом, которым я необоснованно доволен. Созерцайте:

const fnReturnType = (false as true) && fn();

Это работает путем кастинга лжи к литеральному значению истинных, так, чтобы система типов думала, что возвращаемое значение является типом функции, но когда Вы на самом деле выполняете код, это срывает на лжи.

TypeScript является лучшим. :D

99
ответ дан 31 October 2019 в 13:45

Самый легкий путь в TypeScript 2.8:

const foo = (): FooReturnType => {
}

type returnType = ReturnType<typeof foo>;
// returnType = FooReturnType
21
ответ дан 31 October 2019 в 13:45

Нет способа сделать это (см. https://github.com/Microsoft/TypeScript/issues/6606 для отслеживания объекта работы, добавляющего это).

А общее обходное решение является записью что-то как:

var dummy = false && test();
type t2 = typeof dummy;
4
ответ дан 31 October 2019 в 13:45

Код ниже работ, не выполняя функцию. Это из react-redux-typescript библиотеки ( https://github.com/alexzywiak/react-redux-typescript/blob/master/utils/redux/typeUtils.ts)

interface Func<T> {
    ([...args]: any, args2?: any): T;
}
export function returnType<T>(func: Func<T>) {
    return {} as T;
}


function mapDispatchToProps(dispatch: RootDispatch, props:OwnProps) {
  return {
    onFinished() {
      dispatch(action(props.id));
    }
  }
}

const dispatchGeneric = returnType(mapDispatchToProps);
type DispatchProps = typeof dispatchGeneric;
4
ответ дан 31 October 2019 в 13:45

Редактирование: Это больше не нужно с TS 2.8! ReturnType<F> дает тип возврата. См. принятый ответ.

<час>

вариант А на некоторых предыдущих ответах, которые я использую, который работает в strictNullChecks и скрывает гимнастику вывода немного:

function getReturnType<R>(fn: (...args: any[]) => R): R {
  return {} as R;
}

Использование:

function foo() {
  return {
    name: "",
    bar(s: string) { // doesn't have to be shorthand, could be `bar: barFn` 
      return 123;
    }
  }
}

const _fooReturnType = getReturnType(foo);
export type Foo = typeof _fooReturnType; // type Foo = { name: string; bar(s: string): number; }

Это делает , звонят эти getReturnType функция, но это не делает , вызывают исходную функцию. Вы могли предотвращать getReturnType вызов с помощью (false as true) && getReturnType(foo), но IMO это просто делает его более сбивающим с толку.

я просто использовал этот метод с некоторым regexp, находят/заменяют для миграции старого Углового 1.x проект, который имел ~1500 функций фабрики, записанных как это, первоначально в JS, и добавил Foo и т.д. типы ко всему использованию... удивительному взломанный код, который каждый найдет. :)

2
ответ дан 31 October 2019 в 13:45

Если рассматриваемая функция является методом определяемого пользователем класса, можно использовать , декораторы метода в conjuction с Отражают Метаданные для определения типа возврата (функция конструктора) при время выполнения (и с ним, чтобы сделать, поскольку Вы считаете целесообразным).

, Например, Вы могли зарегистрировать его к консоли:

function logReturnType(
    target: Object | Function,
    key: string,
    descriptor: PropertyDescriptor
): PropertyDescriptor | void {
    var returnType = Reflect.getMetadata("design:returntype", target, key);

    console.log(returnType);
}

Просто снимок этот декоратор метода на методе по Вашему выбору и у Вас есть точная ссылка на функцию конструктора объекта, который, предположительно, возвращается из вызова метода.

class TestClass {
    @logReturnType // logs Number (a string representation)
    public test(): number {
        return 42;
    }
}

существует несколько известных ограничений к этому подходу, однако:

  • необходимо явно определить тип возврата на методе, украшенном как таковой, иначе Вы станете неопределенными от Reflect.getMetadata,
  • можно только сослаться на фактические типы, которые также существуют после компиляции; то есть, никакие интерфейсы или дженерики
<час>

кроме того, необходимо будет указать следующие параметры командной строки для компилятора машинописного текста, потому что оба декоратора и отражают, что метаданные являются экспериментальными функциями с записи этого сообщения:

--emitDecoratorMetadata --experimentalDecorators
1
ответ дан 31 October 2019 в 13:45

Я придумал следующее, которое, кажется, работает приятно:

function returnType<A, B, Z>(fn: (a: A, b: B) => Z): Z
function returnType<A, Z>(fn: (a: A) => Z): Z
function returnType<Z>(fn: () => Z): Z
function returnType(): any {
    throw "Nooooo"
}

function complicated(value: number): { kind: 'complicated', value: number } {
    return { kind: 'complicated', value: value }
}

const dummy = (false as true) && returnType(complicated)
type Z = typeof dummy
0
ответ дан 31 October 2019 в 13:45

Нет никакого способа получить тип возврата функции, не выполняя его печально. Это вызвано тем, что, когда TypeScript компилируется в JS, Вы теряете всю информацию относительно типа.

0
ответ дан 31 October 2019 в 13:45

Другие вопросы по тегам:

Похожие вопросы: