Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

WebフロントエンドAdvent Calendar 2024

Day 22

ジェネレータとイテレータの型をみてみよう

Posted at

はじめに

この記事では、ジェネレータとイテレータにどのような型が設定されているかをみていきます。
ジェネレータやイテレータ自体については以下でも取り扱っています。

ジェネレータの型

ジェネレータの型は以下のようになっています。

typescript@5.7.2/node_modules/typescript/lib/lib.es2015.generator.d.ts
interface Generator<T = unknown, TReturn = any, TNext = unknown> extends Iterator<T, TReturn, TNext> {
    // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
    next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
    return(value: TReturn): IteratorResult<T, TReturn>;
    throw(e: any): IteratorResult<T, TReturn>;
    [Symbol.iterator](): Generator<T, TReturn, TNext>;
}

ジェネレータの型Generatorは型引数TTReturnTNextを取ります。
まずはこのTが何を表しているかについてみてみます。

型引数TIteratorResultに渡されているため、そちらの型をみてみます。

typescript@5.7.2/node_modules/typescript/lib/lib.es2015.iterable.d.ts
interface IteratorYieldResult<TYield> {
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
    done: true;
    value: TReturn;
}

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;

IteratorResultは反復結果オブジェクトの型であり、donetrueのときとfalseのときの型のユニオン型となっています。

この型定義から、Tyield式の型であり、TReturnは反復結果オブジェクトのdoneプロパティがtrueのときに返される値の型、つまりジェネレータの返り値の型であることがわかります。

また、TNextnext()メソッドの引数として渡されています。
next()メソッドがyieldに値を渡すときに引数をとりますが、yieldに渡す値の型をTNextとしているわけですね。

ジェネレータはイテレータであり反復可能

ジェネレータはイテレータの一種であり、反復可能なオブジェクトでもあります。
このことが、型の上でも表現されています。

interface Generator<T = unknown, TReturn = any, TNext = unknown> extends Iterator<T, TReturn, TNext>

とあるように、GeneratorIteratorの部分型であることが必要で、これはジェネレータがイテレータでもあることを型の上で要請しています。

また、Generator型は[Symbol.iterator](): Generator<T, TReturn, TNext>;というメソッドを持つことが規定されており、反復可能であることも型の上で要請されています。

[Symbol.iterator]()の返り値の型がIterator型ではなくGenerator型なのは、ジェネレータの[Symbol.iterator]()は自分自身を返すためです。

function* generatorFn() {
    yield 1;
}

const generator = generatorFn();
const genIterator = generator[Symbol.iterator]();

console.log(genIterator === generator); //true

上の例は、ジェネレータとジェネレータの[Symbol.iterator]()メソッドで返されたイテレータが同じオブジェクトであることを示しています。

ジェネレータのメソッドの型

Generatorの型定義から、ジェネレータがもつnext()メソッド、return()メソッド、throw()メソッドがそれぞれ反復結果オブジェクトIteratorResultを返していることが分かります。

    next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
    return(value: TReturn): IteratorResult<T, TReturn>;
    throw(e: any): IteratorResult<T, TReturn>;

next()は引数をもたないか、TNext型の引数を1つだけもち、反復結果オブジェクトが返されることが規定されています。
return()TReturn型の引数をもち、こちらも反復結果オブジェクトが返されます。
throw()については引数がany型となっており、エラーの他に数値や文字列などの値も渡すこと自体はできます(推奨はされません)。

イテレータの型

さいごに、Iterator型についてもみてみます。

typescript@5.7.2/node_modules/typescript/lib/lib.es2015.iterable.d.ts
interface Iterator<T, TReturn = any, TNext = any> {
    // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.
    next(...[value]: [] | [TNext]): IteratorResult<T, TReturn>;
    return?(value?: TReturn): IteratorResult<T, TReturn>;
    throw?(e?: any): IteratorResult<T, TReturn>;
}

イテレータの型もジェネレータの型とほとんど同じものとなっていますが、大きな違いとしては、[Symbol.iterator]()メソッドがない点が挙げられます。
イテレータ自体は必ずしも反復可能ではないため、[Symbol.iterator]()メソッドを型にもっていないわけですね。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address