I have a generator function acting as a consumer to accumulate strings:
function *concatStrings(): Generator<void, string, string> {
let result = '';
try {
while (true) {
const data = yield;
result = data;
}
} finally {
return result;
}
}
const g = concatStrings();
g.next();
g.next('abc');
const r = g.return();
console.log(r);
This works fine, but in TS, it complains
Expected 1 arguments, but got 0.ts(2554)
lib.es2015.generator.d.ts(26, 12): An argument for 'value' was not provided.
How do I create a version of the top that TS doesn't complain, but I also end up with the right types?
CodePudding user response:
The return method is defined as requiring a parameter. If a parameter type is void it does not have to be passed in. We can specify the return type as string | void. This will allow us to not specify the return type:
function *concatStrings(): Generator<void, string | void, string> {
let result = '';
try {
while (true) {
console.log("Loop")
const data = yield;
result = data;
}
} finally {
console.log("Cleanup")
return result;
}
}
const g = concatStrings();
g.next();
g.next('abc');
const r = g.return();
if(typeof r.value === "string") {
console.log(r.value);
}
This will mean that r.value will be void | string, which is less than ideal so you will need to check for string before you can use it.
Another option is to pass in null! as an argument to return g.return(null!); (Playground Link)
CodePudding user response:
The problem is that you're overriding the usual mechanism of the return method by using a return statement in a finally block that throws away the value provided to the method and returns result instead. That's why the signature doesn't match up. In the normal case, the parameter value of the return method is also the TReturn of the generator (example). From MDN:
Generator.prototype.return()Acts as if a
returnstatement is inserted in the generator's body at the current suspended position, which finishes the generator and allows the generator to perform any cleanup tasks when combined with atry...finallyblock.
(Cleanup tasks don't usually include a return statement.)
For what it's worth, I'd encourage you to define and use your generator slightly differently — just use the result of next, no need for that final return, like this:
function *concatStrings(): Generator<string, void, string> {
// −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−^^^^
let result = '';
// (Note no `try`/`finally`, since you don't have resources to clean up)
while (true) {
const data = yield result;
// −−−−−−−−−−−−−−−−−−−−−−−−^^^^^^
result = data;
}
}
const g = concatStrings();
let r: IteratorResult<string, void>;
g.next();
r = g.next("a");
console.log(r.value); // "a"
r = g.next("b");
console.log(r.value); // "ab"
r = g.next("c");
console.log(r.value); // "abc"
This also solves the type problem, because we're no longer going off the standard path. :-)
