Quem é você, objeto? Descobrindo o nome da classe em TypeScript (runtime)

Treinador Online de Python para Iniciantes

Aprenda Python facilmente sem sobrecarga teórica. Resolva tarefas práticas com verificação automática e escreva código diretamente no navegador.

Start Course

Por que você pode precisar do nome da classe em tempo de execução?

\n\n

Imagine: você está escrevendo um sistema complexo em TypeScript. Você tem uma hierarquia de classes — User, Admin, Moderator. Em algum lugar no fundo do código, você recebe um objeto, mas não sabe quem ele é de verdade. Você vê apenas object no console.

\n\n

Ou você está construindo um logger que deve exibir não apenas [Object], mas um nome de classe significativo: [User: John]. Ou você está escrevendo um decorator que deve decidir como processar o objeto, dependendo do seu tipo.

\n\n

É aí que entra a pergunta com milhares de visualizações no Stack Overflow: "Get an object's class name at runtime". Hoje não vamos apenas dar a resposta, mas vamos olhar por baixo do capô do TypeScript e JavaScript para entender como isso realmente funciona.

\n\n

Sim, TypeScript é uma extensão do JavaScript. Toda a mágica dos tipos desaparece após a compilação. Mas o nome da classe não é um tipo, é uma propriedade do protótipo. E ele permanece conosco em tempo de execução.

\n\n

A maneira mais simples: constructor.name

\n\n

Se você já pesquisou essa pergunta, provavelmente já viu esta linha única:

\n\n
class User {\n  constructor(public name: string) {}\n}\n\nconst user = new User("Alice");\nconsole.log(user.constructor.name); // "User"
\n\n

Funciona? Sim. Rápido? Sim. Mas há nuances que podem te pegar se você não souber como isso funciona.

\n\n

Como funciona por baixo dos panos?

\n\n

Cada objeto em JavaScript tem a propriedade constructor. Esta é uma referência à função que criou o objeto. E qualquer função (uma classe também é uma função) tem a propriedade name.

\n\n

Quando você escreve user.constructor.name, o motor faz o seguinte:

\n
    \n
  • Percorre a cadeia de protótipos do objeto user.
  • \n
  • Encontra a propriedade constructor em User.prototype.
  • \n
  • Lê o name da função construtora User.
  • \n
\n\n

É uma operação barata, mas não é gratuita. Na maioria dos casos, você nem vai notar.

\n\n

Quando constructor.name não funciona?

\n\n

Aqui está a pegadinha clássica:

\n\n
const obj = Object.create(null);\nconsole.log(obj.constructor); // undefined\n// console.log(obj.constructor.name); // TypeError!
\n\n

Um objeto criado com Object.create(null) não tem protótipo. Ele não tem constructor. Cuidado.

\n\n

O segundo caso é a minificação. Se você usa um bundler (Webpack, Terser) que renomeia as classes, constructor.name pode retornar algo como t ou e. Isso é um problema apenas para produção, mas é bom saber.

\n\n

Alternativa: instanceof e verificações personalizadas

\n\n

Às vezes você não precisa apenas do nome, mas de uma verificação: "Este objeto é uma instância da classe X?"

\n\n
class Animal {}\nclass Dog extends Animal {}\n\nconst dog = new Dog();\n\nconsole.log(dog instanceof Dog);    // true\nconsole.log(dog instanceof Animal); // true\nconsole.log(dog instanceof Object); // true
\n\n

instanceof funciona através da cadeia de protótipos. Ele verifica se Dog.prototype está na cadeia de protótipos do objeto dog. Se sim — true.

\n\n

Mas instanceof não te dá uma string com o nome. Ele te dá um valor booleano. Para logs ou serialização, isso não serve.

\n\n

Combinando: verificação + nome

\n\n

Você pode escrever uma utilidade que primeiro verifica o tipo e depois retorna o nome:

\n\n
function getClassName(obj: any): string | null {\n  if (obj === null || obj === undefined) return null;\n  if (typeof obj !== 'object' && typeof obj !== 'function') return null;\n\n  // Proteção contra Object.create(null)\n  if (!obj.constructor) return 'Object (no prototype)';\n\n  const name                

Blogs

Book Recommendations