Generator Functions in TypeScript
This article explains generator functions in TypeScript.
You can learn everything from the basics of how to use generator functions to advanced examples combined with asynchronous processing, along with code samples.
YouTube Video
Generator Functions
Generator functions in TypeScript provide similar functionality to JavaScript's generator functions. Generator functions are defined using function*
(a function declaration with an asterisk) and are special functions that can pause and resume execution unlike normal functions.
When a generator function is called, an iterator is returned, which generates values one at a time through this iterator, and you can pause execution using the yield
keyword or send values from outside.
Basic Syntax of Generator Functions
1function* myGenerator(): Generator<number, void, unknown> {
2 yield 1;
3 yield 2;
4 yield 3;
5}
6
7const gen = myGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next().value); // 2
11console.log(gen.next().value); // 3
12console.log(gen.next().done); // true (Iteration finished)
- Define a generator function with
function* myGenerator()
. - The
yield
keyword pauses the function execution while returning a value. - Each time the
next()
method is called, the execution of the generator function resumes and progresses to the nextyield
.
next()
returns an object containing the next value and a done
property. When done
is true
, it indicates that all values have been generated and the generator's processing is complete.
Applications of Generator Functions
Using generator functions allows for easy representation of sequential processing. In the following example, we create a generator function that generates a sequence of numbers.
1function* sequenceGenerator(start: number = 0, step: number = 1) {
2 let current = start;
3 while (true) {
4 yield current;
5 current += step;
6 }
7}
8
9const seq = sequenceGenerator(1, 2);
10
11console.log(seq.next().value); // 1
12console.log(seq.next().value); // 3
13console.log(seq.next().value); // 5
- In this example,
sequenceGenerator
generates an indefinitely increasing sequence of numbers. Useyield
to return values at each step, and generate the next value on subsequent calls.
Passing Values to next
The next()
method can receive a value, which can be sent into the generator function.
1function* adder() {
2 const num1 = yield;
3 const num2 = yield;
4 yield num1 + num2;
5}
6
7const addGen = adder();
8addGen.next(); // Initialization
9addGen.next(5); // Set 5 to num1
10const result = addGen.next(10).value; // Set 10 to num2 and get result
11console.log(result); // 15
- In this example,
next(5)
andnext(10)
send their respective values into the generator function, andyield num1 + num2
returns their sum.
return
and throw
return(value)
can terminate the generator and return the specified value.throw(error)
can throw an exception inside the generator, used for handling exceptions within the generator.
1function* testGenerator() {
2 try {
3 yield 1;
4 yield 2;
5 } catch (e) {
6 console.error("Error caught:", e);
7 }
8}
9
10const gen = testGenerator();
11console.log(gen.next().value); // 1
12gen.throw(new Error("An error occurred!")); // Error caught: An error occurred!
- In this example, the
throw
method is used to generate an error inside the generator, and that error is caught within the generator.
Type Definition in TypeScript
The type definition of a generator function can be specified in the following format.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}
- You specify types in the form of
Generator<YieldType, ReturnType, NextType>
.YieldType
is the type of the value returned byyield
.ReturnType
is the type of the value returned byreturn
.NextType
is the type of the value passed tonext()
.
In the following example, specific types are specified to use the generator safely with types.
1function* numberGenerator(): Generator<number, void, number> {
2 const num1 = yield 1;
3 const num2 = yield num1 + 2;
4 yield num2 + 3;
5}
6
7const gen = numberGenerator();
8
9console.log(gen.next().value); // 1
10console.log(gen.next(10).value); // 12 (10 + 2)
11console.log(gen.next(20).value); // 23 (20 + 3)
Generators and Asynchronous Processing
Generators can also be utilized for asynchronous processing. For example, you can use yield
to wait for the results of asynchronous operations while proceeding with sequential processing. However, in TypeScript or JavaScript, async/await
is more commonly used.
1function* asyncTask() {
2 const result1 = yield fetch("https://codesparklab.com/json/example1.json");
3 console.log(result1);
4
5 const result2 = yield fetch("https://codesparklab.com/json/example2.json");
6 console.log(result2);
7}
Thus, while you can process asynchronous operations sequentially with generators, they are not commonly used for asynchronous processing because Promises and async
/await
are more convenient.
Summary
- Generator functions are special functions defined with
function*
that can return values withyield
while pausing execution of the function. - Use
next()
to resume the generator and receive values. Additionally, you can send values into the generator usingnext(value)
. - You can use
return()
andthrow()
to terminate generator functions or handle errors. - When using generators in TypeScript, you can utilize type definitions to write type-safe code.
Generators are powerful tools that allow you to flexibly control iteration.
You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.