타입스크립트의 제너레이터 함수
이 글은 타입스크립트의 제너레이터 함수에 대해 설명합니다.
코드 샘플과 함께 제너레이터 함수 사용의 기초부터 비동기 처리와 결합된 고급 예제까지 모두 배울 수 있습니다.
YouTube Video
제너레이터 함수
타입스크립트의 제너레이터 함수는 자바스크립트의 제너레이터 함수와 유사한 기능을 제공합니다. 제너레이터 함수는 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}
따라서 제너레이터를 사용해 비동기 작업을 순차적으로 처리할 수는 있지만, Promise와 async
/await
가 더 편리하기 때문에 비동기 처리에서는 일반적으로 사용되지 않습니다.
요약
- 제너레이터 함수는
function*
으로 정의되며, 실행을 멈추고yield
를 통해 값을 반환할 수 있는 특별한 함수입니다. - **
next()
**를 사용하여 제너레이터 실행을 다시 시작하고 값을 받을 수 있습니다. 또한,next(value)
를 사용하여 제너레이터에 값을 보낼 수 있습니다. - **
return()
**과 **throw()
**를 사용하여 제너레이터 함수를 종료하거나 오류를 처리할 수 있습니다. - TypeScript에서 제너레이터를 사용할 때, 타입 정의를 활용하여 타입 안전한 코드를 작성할 수 있습니다.
제너레이터는 반복을 유연하게 제어할 수 있는 강력한 도구입니다.
위의 기사를 보면서 Visual Studio Code를 사용해 우리 유튜브 채널에서 함께 따라할 수 있습니다. 유튜브 채널도 확인해 주세요.