web-dev-qa-db-ja.com

関数の戻り値の型を取得する

次の機能があります。

function test(): number {
    return 42;
}

typeofを使用して、関数のタイプを取得できます。

type t = typeof test;

ここでは、t() => numberになります。

関数の戻り値の型を取得する方法はありますか? t() => numberではなくnumberにしたいのですが。

56
rid

[〜#〜] edit [〜#〜]

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[]

詳細については、 here を参照してください。

TypeScriptは素晴らしいです!


昔ながらのハック

ライアンの答えは、残念ながらもう機能しません。しかし、私はそれを不当に満足しているハックで修正しました。見よ:

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

これは、リテラル値trueにfalseをキャストすることで機能するため、型システムは戻り値を関数の型と見なしますが、実際にコードを実行すると、falseで短絡します。

TypeScriptが最適です。 :D

89
thedayturns

TypeScript 2.8で最も簡単な方法:

const foo = (): FooReturnType => {
}

type returnType = ReturnType<typeof foo>;
// returnType = FooReturnType
18
Jaroslav

これを行う方法はありません(これを追加する作業項目の追跡については https://github.com/Microsoft/TypeScript/issues/6606 を参照してください)。

一般的な回避策は、次のような記述です。

var dummy = false && test();
type t2 = typeof dummy;
4
Ryan Cavanaugh

以下のコードは、関数を実行せずに機能します。 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;
3
eug

問題の関数がユーザー定義クラスのメソッドである場合、 メソッドデコレータ と組み合わせて メタデータを反映 を使用して、runtime(それに合わせて、必要に応じて実行してください)。

たとえば、コンソールにログを記録できます。

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
1
John Weisz

悲しいことに実行せずに関数の戻り値の型を取得する方法はありません。これは、TypeScriptがJSにコンパイルされると、型に関するすべての情報が失われるためです。

0
Luka Jacobowitz

私は次のことを思いつきましたが、うまくいくようです:

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
Werner de Groot