0
1

More than 5 years have passed since last update.

Array.ofのgenerator版

Posted at

自動テスト用に引数で受け取ったものをそのまま返すArray.ofのgenerator版が必要になりました。

単純な書き方

namespace Generator {
  export function* of0(...args: any[]) {
    yield* args;
  }
}
const g0 = Generator.of0(1, '2', true, false, null, undefined, [1], {a:1});
// g0: IterableIterator<any>

適当に作ったのはいいんですが、せっかくTypeScriptで書くのだから、受け取った引数の型を返値の型に反映したいですね。

素直にジェネリクスを使ってみる

namespace Generator {
  export function* of1<T>(...args: T[]) {
    yield* args;
  }
}
//const g1 = Generator.of1(1, '2', true, false, null, undefined, [1], {a:1});
// 違う型を指定すると2番目の引数(正確には2種類目の型の引数)でエラー
const g1 = Generator.of1(1,2,3); // 一種類の型しか指定できない
// g1: IterableIterator<number>

うーむ…一種類だけしか指定できないのではデグレードです。

もうちょっと工夫してジェネリクスを使う

namespace Generator {
  export function* of2<T extends any[]>(...args: T) {
    yield* args;
  }
}

const g2 = Generator.of2(1, '2', true, false, null, undefined, [1], {a:1});
// g2: IterableIterator<any> // やっぱりanyになってしまう

元に戻ってしまいました。

Conditional typesと infer を使う(TypeScript 2.8以降)

namespace Generator {
  export function* of<T extends any[]>(...args: T): IterableIterator<T extends (infer R)[] ? R : never> {
    yield* args;
  }
}

const g = Generator.of(1, '2', true, false, null, undefined, [1], {a:1});
// g: IterableIterator<string | number | boolean | number[] | {a: number;} | null | undefined>
// やった!

ようやくできました。

(おまけ) Array.concatのgenerator版

concatも同じような感じで作れます。
※正確にはArrayのconcatはインスタンスメソッドですが

namespace Generator {
  export function* concat<T extends IterableIterator<any>[]>(...generators: T): IterableIterator<T extends IterableIterator<infer R>[] ? R : never> {
    for (const g of generators) {
      yield* g;
    }
  }
}

const gg = Generator.concat(
  Generator.of(1, '2', true, false),
  Generator.of(null, undefined, [1], {a:1})
);
// gg: IterableIterator<string | number | boolean | number[] | {a: number;} | null | undefined>
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1