简体   繁体   中英

How to define and implement a generator function in an interface and class

In »plain JS« the code would be like that:

class Powers {
  *[Symbol.iterator]() {
    for(let i = 0; i < 10; i++) 
     yield { i, pow: Math.pow(i, i) }
    return null;
  }
}

Then this can be used like so:

const powers = [...new Powers()];

How does a Typescript interface has to like, to define that? Following the docs here I started like that:

interface PowGen {
  //where should the * go?
  [Symbol.iterator]: () => Generator<any, any, any>
}

Exhaustively using »any« like that solves a lot of compiler errors, but also gives me the feeling that there is something wrong in my code. Next to [Symbol.iterator] , the Iterator<> and Generator<> Interfaces list a next , return and throw method. Do I have have to implement them as well?

class Powers implements PowGen {
  *[Symbol.iterator]():Generator<any, any, any> {
    for(let i = 0; i < 10; i++) 
      yield { i, pow: Math.pow(i, i) }
    return null;
  }
}

Just a little example or explanation, which is a bit more verbose than the docs would really help".

The answer was already partly given within the question itself.

The needed interface is:

type YieldType = { type: 'yielded' };
type ReturnType = null;
type ReturnToNext = true | undefined;

interface Foo {
  [Symbol.iterator]: () => Generator<YieldType, ReturnType, ReturnToNext>
}

And the Implementation:

class Bar implements Foo {
  *[Symbol.iterator] () : Generator<YieldType, ReturnType, ReturnToNext> {
    const 
      items = [ { type: 'yielded' }, … ], // this is a really long list
      n = items.length
    ; 

    let 
      i = 0, 
      stop = undefined
    ;

    while (i < n && && stop === undefined) {
      stop = yield items[i];     
      i++;
    }

    return null;
  }
}

Since the type of ReturnToNext accepts undefined it is possible to use the spread operator on an instance of Foo as well. so:

let 
  foo = new Foo(),
  first = foo[Symbol.iterator]().next(true).value // stops the generator
;

or

let items = [...new Foo()];

is possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM