Introdução: A pergunta eterna no Stack Overflow
Você já se perguntou como desenvolvedores experientes em TypeScript obtêm os nomes dos valores de enum? Se você já deu uma olhada no Stack Overflow, certamente viu a pergunta com milhares de visualizações: "How to get names of enum entries?". Parece simples, não? Mas na prática, muitos iniciantes (e não só) tropeçam nesse ponto.
Neste artigo, não vamos apenas dar a resposta pronta. Vamos mergulhar por baixo dos panos do TypeScript e entender como os enum funcionam exatamente, como o compilador os transforma em JavaScript e por que algumas abordagens para obter nomes podem levar a bugs inesperados. Prontos? Vamos lá!
O que é um enum em TypeScript e para que servem seus nomes?
Enum (enumeração) é uma maneira conveniente de definir um conjunto de constantes nomeadas. Em TypeScript, eles podem ser numéricos (padrão) ou de string. Mas o que fazer se você precisar obter o nome de um valor específico? Por exemplo, você recebeu da API um código de status 403 e quer exibir para o usuário uma mensagem compreensível como "Forbidden".
enum HttpStatus { OK = 200, NotFound = 404, Forbidden = 403}
// Nossa tarefa: obter o nome "Forbidden" a partir do valor 403Parece que o TypeScript deveria fornecer um método embutido para isso. Mas não. É preciso escrever sua própria lógica. E é aí que a coisa fica interessante.
Solução "na marra": Object.keys e Object.values
A maneira mais óbvia é usar os métodos Object.keys() ou Object.values(). Muitos iniciantes escrevem algo assim:
function getEnumName(enumObj: any, value: number): string | undefined { const keys = Object.keys(enumObj); return keys.find(key => enumObj[key] === value);}
console.log(getEnumName(HttpStatus, 403)); // "Forbidden" — funciona!Parece lógico, certo? Sim. Mas se você tentar esse código em um enum numérico, uma surpresa o espera. Vamos ver no que nosso HttpStatus é compilado.
Por baixo dos panos: compilação de enum numérico
Quando o TypeScript compila um enum numérico, ele cria um objeto com mapeamento reverso (reverse mapping). Aqui está como fica o JavaScript compilado:
var HttpStatus;(function (HttpStatus) { HttpStatus[HttpStatus["OK"] = 200] = "OK"; HttpStatus[HttpStatus["NotFound"] = 404] = "NotFound"; HttpStatus[HttpStatus["Forbidden"] = 403] = "Forbidden";})(HttpStatus || (HttpStatus = {}));
// No final, o objeto HttpStatus fica assim:// { // "200": "OK", // "404": "NotFound", // "403": "Forbidden", // "OK": 200, // "NotFound": 404, // "Forbidden": 403 // }Viu o truque? O compilador adiciona tanto chaves numéricas quanto chaves de string. Portanto, Object.keys(HttpStatus) retornará não apenas ["OK", "NotFound", "Forbidden"], mas também ["200", "404", "403"]. Isso quebra a lógica da nossa solução simples!
Para contornar isso, é preciso filtrar as chaves numéricas:
function getEnumNameSafe(enumObj: any, value: number): string | undefined { const keys = Object.keys(enumObj).filter(key => isNaN(Number(key))); return keys.find(key => enumObj[key] === value);}Mas esse código parece uma gambiarra. Existe uma maneira melhor?
Enums de string: uma história diferente
Se você usa enums de string, o mapeamento reverso não é criado. Isso simplifica a tarefa:
enum Direction { Up = "UP", Down = "DOWN", Left = "LEFT", Right = "RIGHT"}
// Object.keys(Direction) retornará apenas ["Up", "Down", "Left", "Right"] — perfeito!Mas e se você precisar obter o nome a partir do valor? O mesmo Object.keys funciona perfeitamente:
function getStringEn