Ответ 1
Нет способа сделать это (см. https://github.com/Microsoft/TypeScript/issues/6606 для отслеживания рабочих элементов, добавляя это).
Общим решением является написать что-то вроде:
var dummy = false && test();
type t2 = typeof dummy;
У меня есть следующая функция:
function test(): number {
return 42;
}
Я могу получить тип функции, используя typeof
:
type t = typeof test;
Здесь t
будет () => number
.
Есть ли способ получить возвращаемый тип функции? Я бы хотел, чтобы t
был number
вместо () => number
.
Нет способа сделать это (см. https://github.com/Microsoft/TypeScript/issues/6606 для отслеживания рабочих элементов, добавляя это).
Общим решением является написать что-то вроде:
var dummy = false && test();
type t2 = typeof dummy;
Ответ Ryan больше не работает, к сожалению. Но я изменил его с помощью взлома, который я необоснованно рад. Вот:
const fnReturnType = (false as true) && fn();
Он работает путем литья false для литерального значения true, так что система типа считает, что возвращаемое значение является типом функции, но когда вы действительно запускаете код, это короткие замыкания на false.
TypeScript является лучшим.: D
Невозможно получить возвращаемый тип функции, не выполняя ее печально. Это связано с тем, что когда TypeScript скомпилируется в JS, вы теряете всю информацию о типе.
Код ниже работает без выполнения функции. Он из библиотеки 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;
Если рассматриваемая функция является методом пользовательского класса, вы можете использовать декораторы методов в сочетании с Отразить метаданные, чтобы определить тип возвращаемого значения (функция конструктора) во время выполнения (и с ним делать, как сочтете нужным).
Например, вы можете записать его на консоль:
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
,Кроме того, вам нужно будет указать следующие аргументы командной строки для компилятора typescript, так как оба декоратора и отражают метаданные являются экспериментальными функциями при записи этого сообщения:
--emitDecoratorMetadata --experimentalDecorators
Вариант некоторых предыдущих ответов, которые я использую, который работает в 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 find/replace, чтобы перенести старый проект Angular 1.x, который имел функции ~ 1500 factory, написанные таким образом, первоначально в JS, и добавил типы Foo
etc все использует... удивительный сломанный код, который вы найдете.:)
Я придумал следующее, которое, кажется, работает красиво:
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