ウェブサイト検索

TypeScript - ジェネレーター関数の戻り値の型を取得する方法はありますか?


ジェネレーター関数の戻り値の型を取得したいです。
例えば

function* test(){
  yield 'a';
  yield 123;

  return true;
}

// what I'm trying to get
type A = GetGeneratorReturn<test>; // -> A has type boolean

私が現在いるところ。

type B = ReturnType<ReturnType<typeof test>['next']>['value'];
// B has type `true | "a" | 123`

(ユニオンタイプBの最初の項目を手に入れれば返品タイプがもらえると思っていました)

回答 #1

この問題を含むいくつかの問題について話しているオープンな課題がありますが、かなり古く、他のいくつかの問題が解決されているにもかかわらず、誰も対応している様子はありません。 最近ここやそこでも言及されているのを見かけます。 最も関連性のある課題はこれのようです。 もしこれが気になるなら、GitHubに行ってこれらの課題に👍を付けると良いかもしれません。

現時点では、TypeScriptのジェネレーターの型定義は、yield の型と return の型の区別されていない共用体にしかアクセスできないようです。残念ながら、共用体の型の順序に依存することはできません。それはコンパイラーの実装の詳細であり、X | Y は Y | X と等価なので、コンパイラーは自由にどちらかを変更できます。そして、時々それは実際に行われます。

function* test() {
  yield 'a';
  yield 123;
  return true;
} // function test(): IterableIterator<true | "a" | 123>

function* oops() {
  yield true;
  yield 123;
  return 'a'
} // function oops(): IterableIterator<true | "a" | 123>

oops() の戻り値の型は test() の戻り値の型と まったく同じ です。つまり、合併型の最初/最後の要素を抽出するというあなたの考えは、うまくいかないということです。

特にジェネレーターの定義をいじることができ、いくつかの幻の型が浮かんでいても気にしない場合には、役立つ回避策がある可能性があります。

type Returnable<T> = { __returnedType?: T } & T
const ret = <T>(t: T) => t as Returnable<T>;
type GeneratorReturn<T extends (...args: any) => IterableIterator<any>> =
  ReturnType<T> extends IterableIterator<infer I> ?
  NonNullable<Extract<I, Returnable<unknown>>['__returnedType']> : never

function* test() {
  yield 'a';
  yield 123;
  return ret(true); // only use ret() here
} 

function* oops() {
  yield true;
  yield 123;
  return ret('a'); // only use ret() here
} 

type TestRet = GeneratorReturn<typeof test>; // true
type OopsRet = GeneratorReturn<typeof oops>; // "a"

ある程度はうまくいくけれど、あなたが追求したいものではないかもしれません。まあ、ここでより良い答えを見つけられなくてすみません。頑張ってください!

回答 #2

あなたは今、このようにできる:

type GeneratorReturnType<T extends Generator> = T extends Generator<any, infer R, any> ? R: never;
type TestType =  GeneratorReturnType<ReturnType<typeof test>>; // bool

遊び場

関連記事