Como verificar o tipo de classe em TypeScript: do iniciante ao profissional
\n\nVocê já escreveu em TypeScript, recebeu um objeto de tipo desconhecido e pensou: "E quem é você, afinal?"? Essa pergunta atormenta milhares de desenvolvedores — não é à toa que o tópico class type check in TypeScript acumulou centenas de milhares de visualizações no Stack Overflow. E hoje vamos entender de uma vez por todas como verificar corretamente os tipos de classes em TypeScript.
\n\nNeste artigo, você aprenderá:
\n- \n
- Por que
typeofnão funciona para classes \n - Como usar
instanceofcomo um canivete suíço \n - O que são type guards e como eles salvam seu código \n
- Como criar sua própria verificação de tipo com
is\n - Exemplos reais da prática \n
Vamos nessa!
\n\nO problema: por que typeof é impotente aqui?
\n\nEm JavaScript, existe o operador typeof, que funciona perfeitamente com primitivos:
typeof "hello" // "string"\ntypeof 42 // "number"\ntypeof true // "boolean"\n\nMas quando se trata de classes, typeof falha:
class Dog {}\nclass Cat {}\n\nconst pet = new Dog();\n\ntypeof pet; // "object" — inútil!\ntypeof Dog; // "function" — também não serve\n\nPor quê? Porque as classes em JavaScript são apenas açúcar sintático sobre funções construtoras. O typeof vê apenas "objeto" ou "função", mas não distingue qual classe é.
É aqui que entra o class type check in TypeScript — um arsenal completo de ferramentas que ajudará você a determinar exatamente com qual instância de classe está lidando.
\n\nMétodo 1: instanceof — seu principal aliado
\n\nA maneira mais direta e clara de verificar o tipo de uma classe é o operador instanceof. Ele verifica se a classe está na cadeia de protótipos do objeto:
class Animal {\n name: string;\n constructor(name: string) {\n this.name = name;\n }\n}\n\nclass Dog extends Animal {\n bark() {\n console.log("Woof!");\n }\n}\n\nclass Cat extends Animal {\n meow() {\n console.log("Meow!");\n }\n}\n\nfunction handleAnimal(animal: Animal) {\n if (animal instanceof Dog) {\n // TypeScript sabe que animal é um Dog\n animal.bark();\n } else if (animal instanceof Cat) {\n animal.meow();\n } else {\n console.log(`Animal desconhecido: ${animal.name}`);\n }\n}\n\nconst rex = new Dog("Rex");\nhandleAnimal(rex); // "Woof!"\n\nObserve: após a verificação animal instanceof Dog, o TypeScript automaticamente reduz o tipo (type narrowing) e permite chamar métodos de Dog sem erros. Essa é a magia dos type guards — protetores de tipo embutidos.
Quando o instanceof não funciona?
\n- \n
- Ao trabalhar com diferentes janelas/frames (objetos globais diferentes) \n
- Se as classes forem definidas em módulos diferentes com versões diferentes \n
- Ao verificar interfaces (elas não existem em tempo de execução) \n
Método 2: Type guards personalizados com o operador is
\n\nÀs vezes, o instanceof não é suficiente. Por exemplo, você pode querer verificar não apenas a classe, mas também condições adicionais. É aqui que entram os type guards personalizados com a palavra-chave is:
interface Bird {\n fly(): void;\n layEggs(): void;\n}\n\ninterface Fish {\n swim(): void;\n layEggs(): void;\n}\n\nfunction isFish(pet: Bird | Fish): pet is Fish {\n return (pet as Fish).swim !== undefined;\n}\n\nfunction move(pet: Bird | Fish) {\n if (isFish(pet)) {\n // TypeScript sabe: pet é um Fish\n pet.swim();\n } else {\n pet.fly();\n }\n}\n\nObserve a sintaxe: pet is Fish no tipo de retorno. Isso diz ao TypeScript: "Se esta função retornar true, então o parâmetro pet é um Fish". Agora o TypeScript reduzirá o tipo em todos os lugares onde você usar