Home > database >  How to avoid void type in generators Typescript
How to avoid void type in generators Typescript

Time:01-01

I'm using a generator in my code, that returns strings, but I'm facing the following problem:

const pageUrl = generator.next().value;
const result = catalogPageParser(pageUrl);

Returning the error:

Argument of type 'string | void' is not assignable to parameter of type 'string'.
  Type 'void' is not assignable to type 'string'.ts(2345)

This is easily fixed by either modify the variable like this:

const pageUrl = generator.next().value ?? "some valid url";

Or by modifying the signature of the catalogPageParser function. I do not like any of those solutions, but I cannot think of anything else. Any ideas about how to type that correctly?

I do not like the default value option because there's not a reasonable default value in my case. I also do not like the second because it does not make at all for the function to accept void as a possible argument.

Example

function* someGenerator() {
  yield "url1";
  yield "url2";
}

function acceptsStringOnly(argument: string) {
  console.log(argument);
}

const value = someGenerator().next().value;
acceptsStringOnly(value);

CodePudding user response:

It is because the result of an iterator can have no value if it has already ended. In those cases the property done is false. TypeScript can automatically narrow the type of the value property if you check done:

function* generator() {
    yield 'string1';
    yield 'string2';
    yield 'string3';
}

const iterator = generator();
const result = iterator.next();

let theString: string;

// This fails as in your example
theString = result.value;

if (!result.done) {
    // this works
    theString = result.value;
} else {
    // whatever you have to do if the iterator has ended
}

So the solution to your case can be: 1) check first if done is true and act accordingly (early return, throw, whatever you need); 2) if you know that the iterator will always return a value you can use a non-null assertion.


Your current solution using ?? is likely a good one also, but it of course depends on your needs. One disadvantage I can think of would be that you don't have a proper default value in that context. Managing the case that iterator has ended is, IMHO, a better approach in the general case.

  • Related