TypeScript vai muito além de simples anotações de tipo no JavaScript. Seu verdadeiro potencial está na composição de tipos, inferência automática e manipulação avançada, permitindo que você escreva código mais seguro, legível e eficiente. Neste artigo, exploramos práticas recomendadas que podem elevar suas habilidades e tornar seu código TypeScript mais poderoso.
1. Pense em "Conjuntos" ao Trabalhar com Tipos
Cada tipo em TypeScript pode ser visto como um conjunto de valores. Isso ajuda a entender operações como união (|) e interseção (&).
*Exemplo: *
type Dimensao = { altura: number; largura: number };
type Aparencia = { cor: string; opacidade: number };
type Janela = Dimensao & Aparencia; // { altura: number; largura: number; cor: string; opacidade: number }
Aqui, & cria uma interseção, garantindo que Janela tenha todas as propriedades.
Comparação:
& Interseção: elementos comuns aos dois tipos
`` União: elementos de ambos os tipos
2. Diferencie "Tipo Declarado" e "Tipo Reduzido"
TypeScript ajusta automaticamente os tipos com base no fluxo do código.
Exemplo:
function processar(valor: string | boolean) {
if (typeof valor === 'string') {
console.log(valor.toUpperCase()); // OK, pois TypeScript reduz valor para string
}
}
Isso evita a necessidade de conversões desnecessárias.
3. Prefira União Discriminada a Campos Opcionais
Usar type com uma propriedade discriminatória melhora a segurança do código.
Errado:
type Veiculo = {
tipo: 'carro' | 'moto';
portas?: number;
cilindradas?: number;
};
Correto:
type Carro = { tipo: 'carro'; portas: number };
type Moto = { tipo: 'moto'; cilindradas: number };
type Veiculo = Carro | Moto;
4. Use "Type Predicate" para Evitar "Type Assertion"
Usar um type predicate permite que o TypeScript compreenda automaticamente a especialização de tipos dentro de funções, evitando a necessidade de conversões explícitas (as). Isso melhora a segurança do código e reduz erros inesperados.
Exemplo:
function isCarro(veiculo: Veiculo): veiculo is Carro {
return veiculo.tipo === 'carro';
}
const veiculos: Veiculo[] = obterVeiculos();
const carros = veiculos.filter(isCarro); // TypeScript agora sabe que isso é um Carro[]
Outro Exemplo:
type Animal = { tipo: 'cachorro' | 'gato'; som?: string };
type Cachorro = { tipo: 'cachorro'; som: 'latido' };
type Gato = { tipo: 'gato'; som: 'miado' };
type Especie = Cachorro | Gato;
function isCachorro(animal: Especie): animal is Cachorro {
return animal.tipo === 'cachorro';
}
const animais: Especie[] = [
{ tipo: 'cachorro', som: 'latido' },
{ tipo: 'gato', som: 'miado' }
];
const apenasCachorros = animais.filter(isCachorro);
console.log(apenasCachorros); // [{ tipo: 'cachorro', som: 'latido' }]
5. Controle como Tipos de União São Distribuídos
TypeScript distribui tipos em uniões automaticamente. Podemos alterar isso com colchetes:
Exemplo:
type ToList<T> = [T] extends [Array<unknown>] ? T : T[];
type Resultado = ToList<string | number>; // Agora é (string | number)[]
6. Utilize "Exaustividade" em switch para Evitar Casos Não Tratados
Usar never pode ajudar a garantir que todas as possibilidades sejam cobertas:
function calcularDesconto(produto: Produto) {
switch (produto.categoria) {
case 'eletronico':
return produto.preco * 0.9;
case 'vestuario':
return produto.preco * 0.8;
default:
const exaustivo: never = produto;
throw new Error('Categoria desconhecida');
}
}
7. Prefira type a interface
Use type, a menos que precise de declaration merging ou de OO:
type Cliente = { nome: string; idade: number; email: string };
8. Use Tuplas ao Invés de Arrays Genéricos
type Coordenada = [number, number, string];
const minhaLocalizacao: Coordenada = [40.7128, -74.0060, 'Nova York'];
9. Controle a Especificidade da Inferência de Tipos
Use as const para restringir valores.
Use satisfies para validar sem alterar inferência:
const produto = { preco: 100, nome: 'Notebook' } satisfies { preco: number; nome?: string };
console.log(produto.nome.length); // Ok, pois TypeScript sabe que nome não é `undefined`
**10. Evite Código Repetitivo com Manipulação de Tipos
Exemplo:
type Funcionario = { nome: string; cargo: string; salario: number };
type DadosSalariais = Pick<Funcionario, 'cargo' | 'salario'>;
Isso elimina redundância ao criar novos tipos baseados em tipos existentes.
Top comments (0)