Introdução
O TypeScript usa um conceito frequentemente apelidado de Duck Typing (Tipagem Pato). A regra de ouro é:
"Se um animal anda como um pato, nada como um pato e grasna como um pato, então, para todos os efeitos, ele é um pato."
No TypeScript, isso significa que o compilador não se importa com a "certidão de nascimento" (o nome) do objeto. Ele só se importa com o que o objeto tem por dentro (suas propriedades e métodos).
A tipagem estrutural existe no TypeScript porque o JavaScript (a linguagem base) é extremamente dinâmico. Essa abordagem permite que o TypeScript traga segurança para o código sem perder a flexibilidade natural do JavaScript de criar objetos dinamicamente.
Tipagem Nominal vs. Tipagem Estrutural
Para deixar isso bem claro, vamos ver como as coisas funcionam em outras linguagens versus como funcionam no TypeScript.
O mundo Nominal (Java, C#, C++)
Nestas linguagens, o nome do tipo é a lei.
Se você criar uma classe Cachorro e uma classe Gato, mesmo que ambas tenham apenas uma propriedade nome: string, um Cachorro nunca poderá ser aceito onde um Gato é esperado. Eles têm nomes diferentes, logo, são incompatíveis.
O mundo Estrutural (TypeScript)
No TypeScript, a estrutura é a lei.
Veja o exemplo abaixo:
interface Cachorro {
nome: string;
}
interface Gato {
nome: string;
}
let meuCachorro: Cachorro = { nome: "Rex" };
let meuGato: Gato;
// Isso funciona perfeitamente no TypeScript!
meuGato = meuCachorro;
Eles têm nomes diferentes (Cachorro e Gato), mas como ambos exigem apenas uma propriedade nome do tipo string, o TypeScript olha para eles e diz: "Eles têm a mesma estrutura, então são compatíveis".
A Regra do “Mínimo Necessário”
A compatibilidade estrutural não exige que os objetos sejam 100% idênticos. A regra real é: o objeto que está sendo atribuído deve ter pelo menos as propriedades exigidas. Ele pode ter propriedades a mais, mas nunca a menos.
interface Ponto2D {
x: number;
y: number;
}
interface Ponto3D {
x: number;
y: number;
z: number;
}
let ponto3: Ponto3D = { x: 10, y: 20, z: 30 };
// Funciona! Ponto3D tem 'x' e 'y'. O TypeScript ignora o 'z' extra.
let ponto2: Ponto2D = ponto3;
// ERRO! Ponto2D não tem a propriedade 'z', que é exigida pelo Ponto3D.
let outroPonto3: Ponto3D = ponto2;
O Cuidado com os Literais (O "Gotcha")
Há uma pequena exceção que costuma confundir quem está começando. Se você tentar atribuir um objeto "direto" (que chamamos de literal) com propriedades a mais, o TypeScript vai reclamar para te proteger de erros de digitação:
interface Usuario {
nome: string;
}
// ERRO: O TypeScript é rigoroso com objetos criados diretamente na atribuição.
// Ele diz: "Você está tentando passar uma 'idade', mas Usuario não pede isso".
let user1: Usuario = { nome: "Ana", idade: 25 };
// FUNCIONA: Se o objeto já existe em outra variável, o TypeScript volta para
// a regra estrutural padrão e aceita, ignorando a propriedade extra.
let info = { nome: "Ana", idade: 25 };
let user2: Usuario = info;
Top comments (0)