Генераторные функции в TypeScript
Эта статья объясняет генераторные функции в TypeScript.
Вы можете изучить всё — от основ использования функций-генераторов до продвинутых примеров с асинхронной обработкой, включая примеры кода.
YouTube Video
Генераторные функции
Генераторные функции в TypeScript обеспечивают функциональность, аналогичную генераторным функциям в JavaScript. Генераторные функции определяются с помощью function*
(объявление функции с звездочкой) и являются специальными функциями, которые могут приостанавливать и возобновлять выполнение, в отличие от обычных функций.
Когда вызывается генераторная функция, возвращается итератор, который генерирует значения по одному через этот итератор, причем выполнение может быть приостановлено с помощью ключевого слова yield
или значения могут быть переданы извне.
Базовый синтаксис генераторных функций
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)
- Определение генераторной функции с помощью
function* myGenerator()
. - Ключевое слово
yield
приостанавливает выполнение функции и возвращает значение. - Каждый раз при вызове метода
next()
выполнение генераторной функции возобновляется и продолжается до следующего оператораyield
.
next()
возвращает объект, содержащий следующее значение и свойство done
. Когда done
равно true
, это означает, что все значения сгенерированы и выполнение генераторной функции завершено.
Применение генераторных функций
Использование генераторных функций позволяет удобно представлять последовательную обработку. В следующем примере мы создаем генераторную функцию, которая генерирует последовательность чисел.
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
- В этом примере
sequenceGenerator
генерирует бесконечно возрастающую последовательность чисел. Используйтеyield
для возврата значений на каждом этапе и генерируйте следующее значение при последующих вызовах.
Передача значений в next
Метод next()
может принимать значение, которое может быть передано в генераторную функцию.
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
- В этом примере
next(5)
иnext(10)
передают свои значения в генераторную функцию, аyield num1 + num2
возвращает их сумму.
return
и throw
return(value)
может завершить работу генератора и вернуть указанное значение.throw(error)
может вызвать исключение внутри генератора, используется для обработки исключений внутри генератора.
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!
- В этом примере метод
throw
используется для создания ошибки внутри генератора, и эта ошибка перехватывается самим генератором.
Определение типов в TypeScript
Определение типа функции-генератора может быть указано в следующем формате.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}
- Вы указываете типы в формате
Generator<YieldType, ReturnType, NextType>
.YieldType
— это тип значения, возвращаемого операторомyield
.ReturnType
— это тип значения, возвращаемого операторомreturn
.NextType
— это тип значения, передаваемого в функциюnext()
.
В следующем примере указаны конкретные типы для безопасного использования генератора с типами.
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)
Генераторы и асинхронная обработка
Генераторы также могут использоваться для асинхронной обработки. Например, вы можете использовать yield
, чтобы ожидать результаты асинхронных операций при последовательной обработке. Однако в TypeScript или JavaScript чаще используются async/await
.
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}
Таким образом, хотя генераторы можно использовать для последовательной обработки асинхронных операций, они редко применяются для асинхронной обработки, так как Promises и async
/await
более удобны.
Резюме
- Функции-генераторы — это специальные функции, определяемые с использованием
function*
, которые могут возвращать значения с помощьюyield
, приостанавливая выполнение функции. - Используйте
next()
, чтобы возобновить работу генератора и получить значения. Кроме того, вы можете передавать значения в генератор, используяnext(value)
. - Вы можете использовать
return()
иthrow()
, чтобы завершить работу функции-генератора или обработать ошибки. - При использовании генераторов в TypeScript вы можете применять определения типов для написания безопасного кода.
Генераторы — это мощные инструменты, позволяющие гибко управлять итерацией.
Вы можете следовать этой статье, используя Visual Studio Code на нашем YouTube-канале. Пожалуйста, также посмотрите наш YouTube-канал.