Desafio TypeScript
Comparando enum, const enum e união de literais
Enunciado
Implemente três versões de um mesmo conceito: um enum chamado LogLevelEnum, um const enum chamado LogLevelConstEnum e um tipo união de literais LogLevelUnion. Cada um deve representar os níveis DEBUG, INFO, WARN, ERROR. Escreva uma função logMessage(level: LogLevelUnion, message: string): void que imprime a mensagem formatada de acordo com o nível (ex.: [DEBUG] mensagem). Em seguida, teste a função com todos os níveis usando o tipo união. Depois, mostre que os valores do enum e do const enum podem ser usados como argumentos para a função (se forem compatíveis).
Requisitos
- Definir
enum LogLevelEnumcom valores string. - Definir
const enum LogLevelConstEnumcom valores string. - Definir
type LogLevelUnioncomo união de literais. - Implementar
logMessageque aceitaLogLevelUnione formata a mensagem. - Chamar
logMessagecom todos os níveis da união e também com valores do enum e const enum (se possível).
Código inicial
// Defina enum, const enum e união de literais
// Implemente logMessage
// Teste com todos os níveis
Saída esperada
[DEBUG] Iniciando
[INFO] Processando
[WARN] Atenção
[ERROR] Falha
[DEBUG] Do enum
[INFO] Do const enum
Ver dica
Enums string são compatíveis com uniões de literais se os valores forem os mesmos. Use as const para criar um objeto com os valores e derivar o tipo.
Mostrar solução
// Enum string
enum LogLevelEnum {
DEBUG = 'DEBUG',
INFO = 'INFO',
WARN = 'WARN',
ERROR = 'ERROR'
}
// Const enum string (será inlined na compilação)
const enum LogLevelConstEnum {
DEBUG = 'DEBUG',
INFO = 'INFO',
WARN = 'WARN',
ERROR = 'ERROR'
}
// União de literais
type LogLevelUnion = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR';
// Função que aceita a união
function logMessage(level: LogLevelUnion, message: string): void {
console.log(`[${level}] ${message}`);
}
// Testes com a união
logMessage('DEBUG', 'Iniciando');
logMessage('INFO', 'Processando');
logMessage('WARN', 'Atenção');
logMessage('ERROR', 'Falha');
// Testes com valores do enum e const enum (são strings literais compatíveis)
logMessage(LogLevelEnum.DEBUG, 'Do enum');
logMessage(LogLevelConstEnum.INFO, 'Do const enum');
Passo a passo
- Definimos
LogLevelEnumcom valores string explícitos. - Definimos
LogLevelConstEnumda mesma forma, mas comconst enum. - Definimos
LogLevelUnioncomo união dos literais string. - A função
logMessagerecebelevel: LogLevelUnione formata a mensagem. - Chamamos a função com strings literais que correspondem à união.
- Chamamos a função com
LogLevelEnum.DEBUGeLogLevelConstEnum.INFO. Como os valores são strings literais idênticas, são compatíveis com a união.
Por que funciona
Enums string (e const enums) produzem valores que são strings literais. A união de literais aceita qualquer string que corresponda exatamente aos literais definidos. Portanto, LogLevelEnum.DEBUG tem tipo LogLevelEnum.DEBUG (que é 'DEBUG'), compatível com LogLevelUnion. Já const enum é apagado na compilação, e seus usos são substituídos pelo valor literal, então também é compatível.
Erros comuns
- Usar enum numérico: se
LogLevelEnumfosse numérico,LogLevelEnum.DEBUGseria um número e não seria compatível com a união de strings. - Esquecer de exportar: se os tipos estiverem em módulos separados, é preciso exportar/importar.
- Achar que const enum não pode ser usado como valor:
const enumsó pode ser usado em contextos onde o valor é conhecido em tempo de compilação; não pode ser usado como objeto.
Outra forma de resolver
Usar apenas um objeto as const:
const LogLevel = {
DEBUG: 'DEBUG',
INFO: 'INFO',
WARN: 'WARN',
ERROR: 'ERROR'
} as const;
type LogLevelUnion = typeof LogLevel[keyof typeof LogLevel];
Isso evita enums e mantém tudo em JavaScript puro.
Saída esperada
[DEBUG] Iniciando
[INFO] Processando
[WARN] Atenção
[ERROR] Falha
[DEBUG] Do enum
[INFO] Do const enum