in / out Variância (covariância e contravariância)

Última atualização: 2026-10-22

in / out Variância (covariância e contravariância)

A variância descreve como um parâmetro de tipo dentro de um tipo composto afeta a compatibilidade geral: retornos são covariantes (subtipos substituem), parâmetros são contravariantes (funções que aceitam supertipos substituem). Atribuibilidade de funções e compatibilidade de interfaces aninhadas seguem tudo isso — uma vez compreendida, "por que esta atribuição dá erro ou não" tem uma resposta sistemática.

GrupoGenéricos
TipoSintaxe
Modo strictNão necessário

ℹ️ Info O editor transpila TypeScript para JavaScript e o executa (sem verificação de tipos); veja a Saída de cada exemplo para o resultado da verificação.

📝 Sintaxe

// TS 4.7+ permite anotações de variância explícitas (por padrão, inferidas estruturalmente)
interface Producer<out T> { produce(): T; }        // covariante: apenas produz T
interface Consumer<in T> { consume(v: T): void; }   // contravariante: apenas consome T

// As regras naturais da atribuição de funções
let handleDog: (d: Dog) => void = handleAnimal;          // OK: contravariância de parâmetro
const adoptAnimal: (tag: string) => Animal = adoptDog;   // OK: covariância de retorno

⚙️ Parâmetros

<out T>T aparece apenas em posições de saída (retornos): Producer<Dog> pode servir como Producer<Animal>
<in T>T aparece apenas em posições de entrada (parâmetros): Consumer<Animal> pode servir como Consumer<Dog>
<in out T>Leitura e escrita ambas expostas: tipos estritamente idênticos exigidos, senão incompatível

Retorno:A variância é uma regra de compatibilidade sem código em execução; ela decide apenas "o que pode ser atribuído a quê".

▶ Exemplo

Edite o código abaixo e clique em Testar para ver o resultado transpilado:

Saída:

Rex eats food
Rex-A1 eats food

(Saída de execução após a transpilação; o inverso não vale — atribuir uma função que só trata Dog ao espaço (a: Animal) => void é rejeitado pelo compilador, que é justamente a contravariância de parâmetros barrando uma atribuição insegura)

💡 Observações

ℹ️ Info Intuição: "saídas podem ser mais específicas (co), consumidores podem ser mais amplos (contra)" — um dono de pet que aceita qualquer Animal consegue cuidar de um Dog; um canil que produz Dogs atende qualquer necessidade de Animal.
⚠️ Atenção Arrays mutáveis tanto produzem quanto consomem (bivariância) — o buraco clássico para atribuições inseguras; ao projetar interfaces genéricas, decida se T entra ou sai, depois anote in/out.
💡 Dica As anotações explícitas do TS 4.7 servem sobretudo como documentação e velocidade: a inferência estrutural costuma acertar, mas in/out torna verificações profundas mais rápidas, a intenção mais clara e as mensagens de erro mais diretas.
Mais casos em breve.

📚 Tutoriais relacionados

❓ Perguntas frequentes

P Covariância vs contravariância em uma frase?
R Olhe onde o parâmetro de tipo aparece: posições de saída (retornos) são covariantes — subtipos continuam compatíveis; posições de entrada (parâmetros) são contravariantes — supertipos continuam compatíveis. Tanto entrada quanto saída significa invariância (estritamente idênticos).
P Por que parâmetros de função são contravariantes, e não covariantes?
R Contraexemplo: se (d: Dog) => void pudesse preencher (a: Animal) => void, quem chamasse passando Cat quebraria. Mas (a: Animal) => void preenchendo (d: Dog) => void é seguro — ele trata qualquer Animal, Dog incluído.
P Quando é preciso anotar in/out explicitamente?
R Quando as posições dos parâmetros são complexas, a inferência estrutural é lenta ou os resultados parecem contraintuitivos (emitters de eventos, interfaces profundamente aninhadas). Código do dia a dia pode contar com a inferência — não é preciso anotar em todo lugar.
Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%