Scelta tra valori letterali ed enumerazioni di stringhe TypeScript
Tempo di lettura: 4 minuti

Uno dei vantaggi di far parte di un team di sviluppo è che sei esposto a una varietà di costrutti linguistici, modelli e stili di codifica. Questo può evitare di rimanere bloccati in un solco in cui ogni problema è un chiodo che deve essere martellato. Caso in questione, di recente stavo lavorando su un componente angolare che aveva la seguente definizione di tipo:

type TimeFrame="hour" | 'day' | 'week' | 'month' | 'year';



Non avevo mai visto questo particolare tipo prima, quindi l’ho cercato. Questa è stata la mia introduzione al TypeScript Unione letterale di stringhe. È un’alternativa leggera al enumerazioni di stringhe con cui ero abituato a lavorare. Potrebbe essere una scelta migliore di un enum in alcune circostanze. Per questo motivo, vale la pena confrontare i pro ei contro di ciascuno, che è esattamente ciò che faremo oggi.

La differenza tra enumerazioni di stringhe e unioni letterali di stringhe

In superficie, il Lasso di tempo il tipo sopra assomiglia molto a un enum, in quanto definisce diverse costanti di stringa:

type TimeFrames="hour" | 'day' | 'week' | 'month' | 'year';

enum TimeFrames {
HOUR = 'hour',
DAY = 'day',
WEEK = 'week',
MONTH = 'month',
YEAR = 'year'
}


Dimensione codice

Una delle principali differenze può essere osservata solo osservando il codice trapiantato. Nel caso di unioni di stringhe letterali, TypeScript non ha bisogno di generare codice, perché viene utilizzato solo in fase di compilazione. Di conseguenza, il codice JavaScript (JS) generato sarà di dimensioni notevolmente inferiori. Contrasta questo con le enumerazioni di stringhe, che possono comportare un codice JS significativamente maggiore, come evidenziato dal codice JS trapiantato per l’enumerazione TimeFrames:

var TimeFrames;

(function (TimeFrames) {
TimeFrames["HOUR"] = "hour";
TimeFrames["DAY"] = "day";
TimeFrames["WEEK"] = "week";
TimeFrames["MONTH"] = "month";
TimeFrames["YEAR"] = "year";
})(TimeFrames || (TimeFrames = {}));


Se non ti interessano i valori minuscoli, puoi definire anche un enum come questo:

enum TimeFrames {
'hour',
'day',
'week',
'month',
'year'
}


Per comodità di digitare meno, ti ritroverai con JavaScript ancora più prolisso!

var TimeFrames;

(function (TimeFrames) {
TimeFrames[TimeFrames["hour"] = 0] = "hour";
TimeFrames[TimeFrames["day"] = 1] = "day";
TimeFrames[TimeFrames["week"] = 2] = "week";
TimeFrames[TimeFrames["month"] = 3] = "month";
TimeFrames[TimeFrames["year"] = 4] = "year";
})(TimeFrames || (TimeFrames = {}));


I valori delle enumerazioni di stringhe sono opachi

Per tutto quel codice extra, ottieni valori opachi, il che significa che i metodi che accettano quel tipo enum, non hanno bisogno di conoscere le stringhe esatte che ogni valore enum contiene. In effetti, anche gli sviluppatori che usano l’enum non devono preoccuparsi dei valori effettivi. Vuoi un anno TimeFrame? Quindi TimeFrames.YEAR è quello che stai cercando. Diamine, potrebbe facilmente essere un numero sotto le coperte. Nel caso di enumerazioni di stringhe, puoi confrontare i valori con altre stringhe, come in:

if (timeFrame === TimeFrames.YEAR) {
// do something
}


Come bonus, i popolari ambienti di sviluppo integrato (IDE) come Visual Studio Code possono aiutarci a scegliere rapidamente il valore da un elenco di possibili valori tramite il completamento automatico:

Contrastalo con il tipo union, dove devi ancora digitare la stringa completa ogni volta che crei una nuova variabile, ad esempio:

const TIMEFRAME: TimeFrames="year";


Casting Catastrofe

Un’altra, meno ovvia, differenza tra TypeScript String Literal ed Enum diventa evidente solo quando si tenta di forzare una stringa nel tipo più specifico. Di recente ho assistito alla disparità quando si lavora su un miglioramento angolare. Vari tempi sono stati archiviati come Union of String Literals; l’idea era che avrebbero limitato Dati intervallo di tempo, recuperato come stringhe JSON, a quelle valide. Il problema ha sollevato la sua brutta testa quando ho provato a visualizzare i tempi nel modello usando an ngFor ciclo continuo:

type TimeFrames="hour" | 'day' | 'week' | 'month' | 'year';

public readonly TimeFrameData = [
{
chartId: 1,
timeFrame: 'hour',
},
{
chartId: 2,
timeFrame: 'day',
},
];

// in the template:
<div *ngFor="let timeFrameData in TimeFrameData">
<TimeFrameComponent timeFrames={timeFrameData.timeFrame} />;
</div>


Con mio sgomento, l’applicazione non si compilava! Invece, il compilatore si è lamentato del fatto che la stringa di tipo non era assegnabile al tipo TimeFrames. È interessante notare che lo scambio di String Literals con un enum non ha prodotto errori!

enum TimeFrames {
HOUR = 'hour',
DAY = 'day',
WEEK = 'week',
MONTH = 'month',
YEAR = 'year'
}

public readonly TimeFrameData = [
{
chartId: 1,
timeFrame: TimeFrames.HOUR,
},
{
chartId: 2,
timeFrame: TimeFrames.DAY,
},

];

// in the template:
<div *ngFor="let timeFrameData in TimeFrameData">
<TimeFrameComponent timeFrames={timeFrameData.timeFrame} />;
</div>


La chiave era usare i valori enum nell’oggetto TimeFrameData.

Protezioni di tipo per le unioni di stringhe letterali

Poiché i tipi vengono cancellati in fase di compilazione, non è possibile farvi riferimento in alcun modo in fase di esecuzione, incluso nelle protezioni dei tipi. Pertanto, il meglio che puoi fare è ridigitare ogni valore nella tua funzione di convalida. Nella nostra applicazione, stiamo combinando molte proprietà in un unico oggetto, quindi aveva senso usare più proprietà se altro dichiarazioni.

Puoi anche fare qualcosa del genere:

type TimeFrames="hour" | 'day' | 'week' | 'month' | 'year';

type TimeFramesType = {
[key in TimeFrames ] : any
}

export const TimeFramesObj: TimeFramesType = {
hour: '',
day: '',
week: '',
month: '',
year: ''
}

export const isAssignable = (type: string):type is TimeFrames => {
return (type in TimeFramesObj)
}

// true, false
console.log(isAssignable("hour"), isAssignable("dog"));


Il problema che ho con la soluzione di cui sopra è che ho appena scritto un mucchio di codice per evitare il codice extra che verrebbe generato per un enum!

Conclusione

TypeScript Unions of String Literals sembra promettente, ma deve ancora evolversi prima di essere veramente utile. Fino a quando ciò non accadrà, continuerei con le enumerazioni, a meno che la dimensione della tua base di codice JS non superi tutte le altre preoccupazioni.

Source link

Di Simone Serra

Web Designer Freelancer Realizzazione Siti Web Serra Simone Realizzo siti web, portali ed e-commerce con focus specifici sull’usabilità, l’impatto grafico, una facile gestione e soprattutto in grado di produrre conversioni visitatore-cliente. Elaboro siti internet, seguendo gli standard Web garantendo la massima compatibilità con tutti i devices. Sviluppo e-commerce personalizzati, multilingua, geolocalizzati per potervi mettere nelle migliori condizioni di vendita. Posiziono il tuo sito su Google per dare maggiore visibilità alla tua attività sui motori di ricerca con SEO di base o avanzato.