Tipar Funções no TypeScript:
Tudo sobre tipagem de funções no TypeScript. De arrow functions a overloads, com exemplos que você aplica direto no projeto.
Por que isso é importante
Tipar Funções no TypeScript:. Tudo sobre tipagem de funções no TypeScript. De arrow functions a overloads, com exemplos que você aplica direto no projeto.
O Que É Tipagem de Funções no TypeScript
Tipar funções significa definir três coisas: o tipo de cada parâmetro de entrada, o tipo do valor de retorno e, em alguns casos, a assinatura completa da função como um tipo reutilizável. Parece burocracia, mas na prática é o que torna seu código à prova de erros.
No JavaScript, uma função aceita qualquer argumento e retorna qualquer coisa. Você pode chamar soma("a", "b") mesmo que ela espere dois números. O código roda, o resultado vem errado e você descobre o problema três dias depois num log de erro. Todo dev JavaScript já passou por isso pelo menos uma vez.
TypeScript muda esse jogo. Quando você declara function soma(a: number, b: number): number, o compilador garante que ninguém passe string, objeto ou qualquer outra coisa ali. E se a função deveria retornar number mas retorna string, o editor avisa na hora. Feedback instantâneo.
A tipagem funciona tanto em funções tradicionais (function declaration) quanto em arrow functions, function expressions, callbacks e métodos de classe. A sintaxe muda um pouco, mas o conceito é o mesmo: dizer pro TypeScript o que entra e o que sai. Vamos ver cada formato.
Um ponto que confunde no começo: TypeScript infere o tipo de retorno na maioria dos casos. Se a função retorna a + b e ambos são number, o retorno é inferido como number. Mas declarar o retorno explicitamente é uma boa prática em funções complexas. Se você acidentalmente retornar algo errado num dos branches, o compilador pega.
Como Tipar Funções Passo a Passo
Vamos construir passo a passo, do mais simples ao mais avançado. Cada conceito se apoia no anterior.
Exemplos Práticos de Funções Tipadas
Código vale mais que teoria. Veja cada padrão de tipagem em ação com exemplos que você encontra em qualquer projeto real.
Function Declaration e Arrow Function
// Function declaration com tipos
function calcularDesconto(preco: number, percentual: number): number {
return preco - (preco * percentual / 100);
}
// Arrow function com tipos
const calcularImposto = (valor: number, taxa: number): number => {
return valor * taxa;
};
// Arrow function com retorno implícito
const dobrar = (n: number): number => n * 2;
// Uso
const precoFinal = calcularDesconto(100, 15); // 85
const imposto = calcularImposto(100, 0.1); // 10
const resultado = dobrar(21); // 42
A diferença entre declaration e arrow function no TypeScript é só sintática. Ambas suportam tipagem completa. Arrow functions são preferidas em callbacks e componentes React. Function declarations são boas pra funções utilitárias top-level que precisam de hoisting.
Retorno void e Parâmetros Opcionais
// void - função que não retorna valor
function exibirMensagem(texto: string): void {
console.log(`[LOG]: ${texto}`);
// sem return
}
// Parâmetros opcionais com ?
function criarUsuario(
nome: string,
email: string,
telefone?: string // opcional
): void {
console.log(`Nome: ${nome}, Email: ${email}`);
if (telefone) {
console.log(`Telefone: ${telefone}`);
}
}
// Ambas as chamadas são válidas
criarUsuario("Ana", "ana@email.com");
criarUsuario("Ana", "ana@email.com", "11999999999");
Parâmetros opcionais sempre vêm depois dos obrigatórios. Não dá pra ter um opcional no meio e um obrigatório no fim. Se precisa disso, use valores padrão ou passe undefined explicitamente. É uma regra simples que evita confusão.
Valores Padrão e Rest Parameters
// Valores padrão - tipo inferido automaticamente
function listar(pagina = 1, limite = 20): string {
return `Página ${pagina}, mostrando ${limite} itens`;
}
// Rest parameters - recebe múltiplos argumentos
function somarTodos(...numeros: number[]): number {
return numeros.reduce((acc, n) => acc + n, 0);
}
console.log(somarTodos(1, 2, 3, 4, 5)); // 15
console.log(somarTodos(10, 20)); // 30
// Combinando fixo + rest
function log(nivel: string, ...mensagens: string[]): void {
mensagens.forEach(msg => console.log(`[${nivel}] ${msg}`));
}
log("INFO", "Server iniciou", "Porta 3000");
Rest parameters são tipados como array. Se a função recebe números variáveis, é ...numeros: number[]. Se recebe strings, é ...textos: string[]. O spread operator no lado do caller complementa isso: somarTodos(...meuArray).
Function Types e Callbacks
// Definindo o tipo de uma função
type Operacao = (a: number, b: number) => number;
const somar: Operacao = (a, b) => a + b;
const multiplicar: Operacao = (a, b) => a * b;
// Função que recebe outra função como parâmetro
function executar(op: Operacao, x: number, y: number): number {
return op(x, y);
}
console.log(executar(somar, 5, 3)); // 8
console.log(executar(multiplicar, 5, 3)); // 15
// Callback tipado
type Callback = (erro: Error | null, resultado?: string) => void;
function buscarDados(url: string, cb: Callback): void {
try {
const dados = `Dados de ${url}`;
cb(null, dados);
} catch (e) {
cb(e as Error);
}
}
Function types são muito usados em arquiteturas de callback, event handlers e injeção de dependência. Ao definir type Operacao = (a: number, b: number) => number, qualquer função que receba dois numbers e retorne um number é compatível. Isso desacopla o código: a função executar não sabe qual operação vai receber, só sabe o formato.
Function Overloads
// Overloads: mesma função, comportamentos diferentes
// Assinaturas (o que o TypeScript mostra no autocomplete)
function formatar(valor: string): string;
function formatar(valor: number): string;
function formatar(valor: Date): string;
// Implementação
function formatar(valor: string | number | Date): string {
if (typeof valor === "string") {
return valor.trim().toUpperCase();
}
if (typeof valor === "number") {
return valor.toFixed(2);
}
return valor.toISOString().split("T")[0];
}
console.log(formatar(" hello ")); // "HELLO"
console.log(formatar(3.14159)); // "3.14"
console.log(formatar(new Date())); // "2025-07-10"
Overloads são poderosos, mas use com moderação. Na maioria das vezes, union types no parâmetro já resolvem. Overloads brilham quando o tipo de retorno depende do tipo de entrada. Exemplo clássico: uma função que recebe string e retorna string, recebe number e retorna number. Sem overloads, o retorno seria string | number, menos preciso.
Boas Práticas na Tipagem de Funções
Tipar funções vai além de colocar tipos nos parâmetros. Existem práticas que separam código amador de código profissional. A primeira: sempre declare o tipo de retorno em funções exportadas. Funções internas podem usar inferência, mas funções públicas precisam de contrato explícito.
Segunda: mantenha funções com no máximo 3-4 parâmetros. Se precisa de mais, agrupe em um objeto tipado. Em vez de criarPedido(produto, quantidade, preco, desconto, frete), use criarPedido(opcoes: OpcoesPedido). O autocomplete fica melhor e a ordem dos argumentos não importa mais.
Terceira: prefira tipos específicos a tipos genéricos demais. Se uma função recebe um ID, crie type UserId = string em vez de aceitar string direto. Isso documenta a intenção e previne misturar IDs de entidades diferentes. Parece exagero, mas em projetos grandes faz diferença enorme.
Erros Comuns ao Tipar Funções
Cuidado com esses deslizes
Esquecer o tipo de retorno: a inferência geralmente pega, mas em funções complexas com múltiplos returns, declarar o retorno evita surpresas. Se a função deve retornar number, coloque : number explicitamente. Isso pega bugs em branches esquecidos.
Não tipar callbacks: passar uma função sem tipo como parâmetro perde toda a segurança. Crie um type para callbacks e use-o. Sem isso, qualquer função serve como argumento e o erro só aparece em runtime.
Confundir void com undefined: void significa que o retorno deve ser ignorado. undefined é um valor. Uma função void pode retornar undefined, mas uma função que retorna undefined tem tipo de retorno diferente de void. A distinção importa em callbacks.
Usar any nos parâmetros: se a função aceita qualquer tipo, use unknown e faça narrowing dentro dela. any desativa a proteção completamente. É como tirar o freio do carro: funciona até a primeira curva.
Ignorar parâmetros opcionais no corpo: se telefone é opcional (telefone?: string), ele pode ser undefined dentro da função. Sempre verifique antes de usar. O TypeScript avisa, mas muita gente ignora o warning e o bug vai pra produção.
Checklist de Tipagem de Funções
Leve Suas Funções ao Próximo Nível
Funções bem tipadas são a base de qualquer projeto TypeScript sério. No CrazyStack, você não aprende tipagem isolada: você constrói um SaaS completo onde cada função, cada callback, cada handler de rota tem tipos corretos do início ao fim.
É projeto real com Node.js, React e TypeScript. Você termina com código de produção, não com exercício de tutorial. O tipo de experiência que recrutadores procuram.
Continue lendo
Como Tipar Variáveis no TypeScript: Guia Completo
Domine a tipagem de variáveis: string, number, boolean, any, unknown e mais.
Como Usar Interface no TypeScript: Guia Prático
Crie contratos de dados sólidos com interfaces no TypeScript.
Como Usar Generics no TypeScript
Generics tornam funções e classes reutilizáveis sem perder segurança de tipo.
Type vs Interface
Diferenças práticas