Desafio TypeScript
Inferência com `as const` e função genérica
Enunciado
Crie um array const com os estados 'ativo', 'inativo' e 'pendente' usando as const. Escreva uma função genérica primeiro<T>(lista: readonly T[]): T que retorna o primeiro elemento. Use a função para obter o primeiro estado e imprima o valor e seu tipo literal. Depois tente atribuir um valor inválido a uma variável anotada com o tipo do primeiro estado e comente a linha que causaria erro.
Requisitos
- O array deve ser declarado com
as conste conter exatamente os três estados. - A função
primeirodeve ser genérica com parâmetroreadonly T[]e retornoT. - Imprimir o primeiro estado e uma mensagem indicando que o tipo é literal.
- Incluir um comentário mostrando a linha que causaria erro de tipo.
Código inicial
const estados = ['ativo', 'inativo', 'pendente'] as const;
function primeiro<T>(lista: readonly T[]): T {
// implemente
}
// use a função e imprima
Saída esperada
Primeiro estado: ativo
Tipo literal preservado: ativo
Ver dica
Com as const, o array vira uma tupla de literais. O genérico T será inferido como o tipo do primeiro elemento.
Mostrar solução
// `as const` transforma o array em tupla readonly de literais
const estados = ['ativo', 'inativo', 'pendente'] as const;
// Função genérica: T é inferido a partir do array
function primeiro<T>(lista: readonly T[]): T {
return lista[0];
}
// O tipo de `primeiroEstado` é 'ativo' (literal)
const primeiroEstado = primeiro(estados);
console.log(`Primeiro estado: ${primeiroEstado}`);
console.log(`Tipo literal preservado: ${primeiroEstado}`);
// A linha abaixo causaria erro de compilação:
// primeiroEstado = 'inativo'; // erro: 'inativo' não é atribuível a 'ativo'
Passo a passo
const estados = ['ativo', 'inativo', 'pendente'] as const— oas constfaz o compilador tratar o array como tupla readonly de literais, sem widening parastring[].function primeiro<T>(lista: readonly T[]): T— declara um genéricoTe aceita um array readonly deT, retornandoT.return lista[0]— retorna o primeiro elemento; o tipo de retorno éT.const primeiroEstado = primeiro(estados)— o compilador infereTcomo'ativo', pois o array tem literais.- Os
console.logmostram o valor e confirmam que o literal foi preservado. - A linha comentada demonstra que atribuir outro literal causaria erro, provando que o tipo é
'ativo'.
Por que funciona
as const impede o widening: sem ele, o array seria string[] e T seria string. Com ele, cada elemento tem tipo literal e a tupla é readonly. A função genérica preserva o tipo do elemento, então primeiroEstado é 'ativo', não string. Isso é essencial para uniões de literais e APIs type-safe.
Erros comuns
- Esquecer
as const:const estados = ['ativo', 'inativo'];→ tipostring[],primeiroEstadovirastring. - Declarar
function primeiro<T>(lista: T[]): Tsemreadonly→ erro ao passar tupla readonly:readonly ['ativo', ...]não é atribuível aT[]. - Tentar reatribuir
primeiroEstado = 'inativo'sem comentar → erro de compilação, pois o tipo é o literal'ativo'.
Outra forma de resolver
Se quiséssemos aceitar arrays mutáveis também, poderíamos usar Array<T> em vez de readonly T[], mas perderíamos a compatibilidade com tuplas readonly. A versão com readonly é mais flexível e segura.
Saída esperada
Primeiro estado: ativo
Tipo literal preservado: ativo