«A propriedade value não existe»: como fazer TypeScript e DOM se darem bem
\n\nVocê já escreveu um simples manipulador de formulário em TypeScript, executou a compilação — e recebeu uma linha vermelha no console: «The property 'value' does not exist on value of type 'HTMLElement'»? Se sim — você não está sozinho. Esta pergunta acumulou milhares de visualizações no Stack Overflow, e hoje vamos resolvê-la de uma vez por todas.
\n\nO erro ocorre quando você tenta obter .value de um elemento que o TypeScript considera apenas como HTMLElement. O problema é que HTMLElement é um tipo base, e a propriedade value existe apenas em HTMLInputElement, HTMLTextAreaElement e seus descendentes. O TypeScript é rigoroso: ele não permite acessar uma propriedade que (do seu ponto de vista) não existe.
Mas isso não é um bug — é uma funcionalidade. O TypeScript protege você de erros em tempo de execução. Vamos entender como especificar o tipo corretamente e, de quebra, melhorar o desempenho do seu código.
\n\nPor que o TypeScript reclama?
\n\nImagine: você escreve código para um campo de entrada:
\n\nconst input = document.getElementById('myInput');\nconsole.log(input.value); // ❌ Erro!\n\nO método getElementById retorna o tipo HTMLElement | null. HTMLElement não tem a propriedade value. Ele tem innerHTML, className, style — mas não value. O TypeScript diz honestamente: «Não tenho certeza se este elemento tem value».
Mas você tem certeza de que é um <input>. Como explicar isso ao compilador?
Método 1: Type Assertion
\n\nA maneira mais popular e rápida é usar as:
const input = document.getElementById('myInput') as HTMLInputElement;\nconsole.log(input.value); // ✅ Funciona\n\nAgora o TypeScript sabe: é um HTMLInputElement, que tem value. Simples e eficaz. Mas há um detalhe: se o elemento não for realmente um <input> (por exemplo, for um <div>), você receberá undefined em tempo de execução. O TypeScript não vai ajudar — ele acredita nas suas afirmações.
Método 2: Verificação de tipo com instanceof
\n\nUma abordagem mais segura é a verificação em tempo de execução:
\n\nconst element = document.getElementById('myInput');\nif (element instanceof HTMLInputElement) {\n console.log(element.value); // ✅ TypeScript reduz o tipo automaticamente\n} else {\n console.error('O elemento não é um input');\n}\n\nEste método não só resolve o problema de tipos, mas também torna o código mais confiável. Você verifica explicitamente se o elemento é exatamente o que espera. Para fins educacionais, recomendo este método: ele ensina a pensar sobre tipos.
\n\nMétodo 3: Funções genéricas (Generics)
\n\nPara usuários avançados — criação de um wrapper com genéricos:
\n\nfunction getInputElement<T extends HTMLElement>(id: string): T | null {\n const element = document.getElementById(id);\n if (element instanceof T) { // ❌ Não funciona, T é um tipo, não um valor\n return element;\n }\n return null;\n}\n\nInfelizmente, no TypeScript não é possível verificar instanceof com um genérico diretamente. Mas você pode usar sobrecarga de funções ou fábricas. Para projetos simples, os dois primeiros métodos são suficientes.
Otimização de desempenho: por que o tipo importa
\n\nVocê pode perguntar: «Qual a relação dos tipos com a velocidade?» Direta. Quando o TypeScript sabe o tipo exato do elemento, ele gera código JavaScript mais eficiente. Vejamos um exemplo:
\n\n// Ruim: TypeScript não sabe o tipo\nfunction getValue(id: string): string {\n const el = document.getElementById(id);\n // A cada chamada — verificação e type assertion\n return (el as HTMLInputElement).value || '';\n}\n\n// Bo