Funzioni generatrici in TypeScript
Questo articolo spiega le funzioni generatrici in TypeScript.
Puoi imparare tutto, dalle basi dell'utilizzo delle funzioni generatrici fino a esempi avanzati combinati con l'elaborazione asincrona, insieme a esempi di codice.
YouTube Video
Funzioni generatrici
Le funzioni generatrici in TypeScript offrono funzionalità simili a quelle delle funzioni generatrici in JavaScript. Le funzioni generatrici si definiscono utilizzando function*
(una dichiarazione di funzione con un asterisco) e sono funzioni speciali che possono sospendere e riprendere l'esecuzione, a differenza delle funzioni normali.
Quando viene chiamata una funzione generatrice, viene restituito un iteratore, che genera valori uno alla volta tramite questo iteratore. È possibile sospendere l'esecuzione utilizzando la parola chiave yield
o inviare valori dall'esterno.
Sintassi base delle funzioni generatrici
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)
- Definire una funzione generatrice utilizzando
function* myGenerator()
. - La parola chiave
yield
sospende l'esecuzione della funzione restituendo un valore. - Ogni volta che viene chiamato il metodo
next()
, l'esecuzione della funzione generatrice riprende e procede fino al prossimoyield
.
next()
restituisce un oggetto contenente il valore successivo e una proprietà done
. Quando done
è true
, indica che tutti i valori sono stati generati e l'elaborazione del generatore è completa.
Applicazioni delle funzioni generatrici
L'uso delle funzioni generatrici consente una rappresentazione semplice dell'elaborazione sequenziale. Nel seguente esempio, creiamo una funzione generatrice che genera una sequenza di numeri.
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 questo esempio,
sequenceGenerator
genera una sequenza di numeri che cresce indefinitamente. Usareyield
per restituire valori a ogni passo e generare il valore successivo nelle chiamate successive.
Passare valori a next
Il metodo next()
può ricevere un valore, che può essere inviato nella funzione generatrice.
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 questo esempio,
next(5)
enext(10)
inviano i rispettivi valori nella funzione generatrice, eyield num1 + num2
ne restituisce la somma.
return
e throw
return(value)
può terminare il generatore e restituire il valore specificato.throw(error)
può generare un'eccezione all'interno del generatore, utilizzata per gestire le eccezioni all'interno dello stesso.
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 questo esempio, il metodo
throw
viene utilizzato per generare un errore all'interno del generatore, e quell'errore viene catturato all'interno del generatore.
Definizione dei tipi in TypeScript
La definizione del tipo di una funzione generatore può essere specificata nel seguente formato.
1// Generator<YieldType, ReturnType, NextType>
2function* myGenerator(): Generator<number, void, unknown> {
3 yield 1;
4 yield 2;
5 yield 3;
6}
- Specifici i tipi nella forma
Generator<YieldType, ReturnType, NextType>
.YieldType
è il tipo del valore restituito dayield
.ReturnType
è il tipo del valore restituito dareturn
.NextType
è il tipo del valore passato anext()
.
Nel seguente esempio, tipi specifici vengono definiti per utilizzare il generatore in modo sicuro con i tipi.
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)
Generatori e Elaborazione Asincrona
I generatori possono essere utilizzati anche per l'elaborazione asincrona. Ad esempio, puoi usare yield
per attendere i risultati delle operazioni asincrone mentre procedi con l'elaborazione sequenziale. Tuttavia, in TypeScript o JavaScript, async/await
è più comunemente utilizzato.
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}
Pertanto, sebbene tu possa elaborare operazioni asincrone in modo sequenziale con i generatori, essi non sono comunemente utilizzati per l'elaborazione asincrona poiché le Promises e async
/await
sono più convenienti.
Riepilogo
- Le funzioni generatrici sono funzioni speciali definite con
function*
che possono restituire valori conyield
mentre sospendono l'esecuzione della funzione. - Usa
next()
per riprendere il generatore e ricevere valori. Inoltre, puoi inviare valori al generatore utilizzandonext(value)
. - Puoi usare
return()
ethrow()
per terminare le funzioni generatrici o gestire errori. - Quando usi i generatori in TypeScript, puoi sfruttare le definizioni dei tipi per scrivere codice a prova di tipo.
I generatori sono strumenti potenti che ti consentono di controllare l'iterazione in modo flessibile.
Puoi seguire l'articolo sopra utilizzando Visual Studio Code sul nostro canale YouTube. Controlla anche il nostro canale YouTube.