Os Perigos dos ENUMS em TypeScript

enum DayOfWeek {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
}
function isItTheWeekend(day: DayOfWeek) {
switch (day) {
case DayOfWeek.Sunday:
case DayOfWeek.Saturday:
return true;
default:
return false;
}
}
console.log(isItTheWeekend(DayOfWeek.Monday)); // logs 'false'
console.log(isItTheWeekend(2)); // isso é válido?

Por quê isso aconteceu

Escrever este código pode fazer você pensar que descobriu um bug no sistema de tipos TypeScript, mas acontece que esse é o comportamento pretendido para esse tipo de enum. O que fizemos aqui foi criar um enum numérico e, se olharmos para o JavaScript gerado, pode ficar um pouco mais claro:

var DayOfWeek;
(function (DayOfWeek) {
DayOfWeek[(DayOfWeek['Sunday'] = 0)] = 'Sunday';
DayOfWeek[(DayOfWeek['Monday'] = 1)] = 'Monday';
DayOfWeek[(DayOfWeek['Tuesday'] = 2)] = 'Tuesday';
DayOfWeek[(DayOfWeek['Wednesday'] = 3)] = 'Wednesday';
DayOfWeek[(DayOfWeek['Thursday'] = 4)] = 'Thursday';
DayOfWeek[(DayOfWeek['Friday'] = 5)] = 'Friday';
DayOfWeek[(DayOfWeek['Saturday'] = 6)] = 'Saturday';
})(DayOfWeek || (DayOfWeek = {}));

Quando isso é útil

Você pode estar pensando que isso não parece particularmente útil, pois realmente quebra todo o aspecto de segurança de tipo do TypeScript se você puder passar um número arbitrário para uma função que espera um enum, então por que isso é útil?

const day: DayOfWeek = 3;

Controlando um Enums de Números

Como o número de um membro de enum é definido com base na ordem em que aparecem na definição de enum, pode ser um pouco opaco quanto ao valor até que você inspecione o código gerado, mas isso é algo que podemos controlar:

enum FileState {
Read = 1,
Write = 2,
}

Sinalizadores de Bits (Bit Flags)

Mas há outro motivo pelo qual isso pode ser útil: usar enums para sinalizadores de bits. Vamos pegar nosso FileState enum acima e adicionar um novo estado para o arquivo ReadWrite:

enum FileState {
Read = 1,
Write = 2,
ReadWrite = 3,
}
const file = await getFile('/path/to/file', FileState.Read | FileState.Write);
enum FileState {
Read = 1,
Write = 2,
ReadWrite = Read | Write,
}
enum Foo {
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
}

Controlando Índices

Vimos que um enum terá um valor numérico atribuído a ele por padrão ou podemos fazer isso explicitamente em todos eles, mas também podemos fazer em um subconjunto deles:

enum DayOfWeek {
Sunday,
Monday,
Tuesday,
Wednesday = 10,
Thursday,
Friday,
Saturday,
}
var DayOfWeek;
(function (DayOfWeek) {
DayOfWeek[(DayOfWeek['Sunday'] = 0)] = 'Sunday';
DayOfWeek[(DayOfWeek['Monday'] = 1)] = 'Monday';
DayOfWeek[(DayOfWeek['Tuesday'] = 2)] = 'Tuesday';
DayOfWeek[(DayOfWeek['Wednesday'] = 10)] = 'Wednesday';
DayOfWeek[(DayOfWeek['Thursday'] = 11)] = 'Thursday';
DayOfWeek[(DayOfWeek['Friday'] = 12)] = 'Friday';
DayOfWeek[(DayOfWeek['Saturday'] = 13)] = 'Saturday';
})(DayOfWeek || (DayOfWeek = {}));
enum DayOfWeek {
Sunday,
Monday,
Tuesday,
Wednesday = 10,
Thursday = 2,
Friday,
Saturday,
}
var DayOfWeek;
(function (DayOfWeek) {
DayOfWeek[(DayOfWeek['Sunday'] = 0)] = 'Sunday';
DayOfWeek[(DayOfWeek['Monday'] = 1)] = 'Monday';
DayOfWeek[(DayOfWeek['Tuesday'] = 2)] = 'Tuesday';
DayOfWeek[(DayOfWeek['Wednesday'] = 10)] = 'Wednesday';
DayOfWeek[(DayOfWeek['Thursday'] = 2)] = 'Thursday';
DayOfWeek[(DayOfWeek['Friday'] = 3)] = 'Friday';
DayOfWeek[(DayOfWeek['Saturday'] = 4)] = 'Saturday';
})(DayOfWeek || (DayOfWeek = {}));

Enums não numéricos

Até agora, discutimos apenas enums que são numéricos ou que atribuem números explicitamente a valores de enum, mas um enum não precisa ser um valor numérico, pode ser qualquer coisa constante ou valor calculado:

enum DayOfWeek {
Sunday = 'Sun',
Monday = 'Mon',
Tuesday = 'Tues',
Wednesday = 'Wed',
Thursday = 'Thurs',
Friday = 'Fri',
Saturday = 'Sat',
}
var DayOfWeek;
(function (DayOfWeek) {
DayOfWeek['Sunday'] = 'Sun';
DayOfWeek['Monday'] = 'Mon';
DayOfWeek['Tuesday'] = 'Tues';
DayOfWeek['Wednesday'] = 'Wed';
DayOfWeek['Thursday'] = 'Thurs';
DayOfWeek['Friday'] = 'Fri';
DayOfWeek['Saturday'] = 'Sat';
})(DayOfWeek || (DayOfWeek = {}));
const day: DayOfWeek = 'Mon';
const day = 'Mon' as DayOfWeek;
enum Confusing {
A,
B = 1,
C = 1 << 8,
D = 1 + 2,
E = 'Hello World'.length,
}
enum MoreConfusion {
A,
B = 2,
C = 'C',
}

Conclusão

Enums no TypeScript são uma adição muito útil à linguagem JavaScript. Quando usados ​​corretamente, eles podem ajudar a esclarecer a intenção de normalmente “valores mágicos” (strings ou números) que podem existir em um aplicativo e fornecer uma visão segura de tipos deles. Mas, como qualquer ferramenta na caixa de ferramentas de alguém, se forem usadas incorretamente, pode não ficar claro o que representam e como devem ser usadas.

Créditos

--

--

☕🇳🇿 - https://eduardorabelo.me

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store