Template Type Checking no Angular CLI
A verificação de tipos em templates do Angular é uma funcionalidade poderosa que garante a integridade e a robustez dos seus aplicativos ao detectar erros de tipo em expressões e bindings dentro dos templates. Assim como o TypeScript identifica erros de tipo no seu código, o Angular aplica essa verificação dentro dos templates, reportando qualquer inconsistência encontrada. Essa abordagem promove um desenvolvimento mais seguro e ajuda a evitar bugs complexos que podem surgir durante a execução do aplicativo.
O Que é o Template Type Checking?
O Template Type Checking é um recurso do Angular CLI que verifica as expressões e os bindings dentro dos seus templates, comparando-os com os tipos definidos no seu código TypeScript. Essa verificação ajuda a identificar erros de tipo que poderiam causar problemas em tempo de execução, como acessar propriedades inexistentes de um objeto ou passar argumentos inválidos para um método.
Imagine o Template Type Checking como um radar que escaneia cada canto da sua nave espacial Angular, buscando por anomalias e falhas estruturais. Com essa ferramenta, você pode detectar e corrigir problemas em seus templates antes que eles causem danos à sua aplicação, garantindo uma viagem segura e tranquila.
No Angular, existem três modos principais de verificação de tipos em templates, os quais são configurados através das flags fullTemplateTypeCheck
e strictTemplates
nas opções do compilador do Angular. Cada modo oferece um nível diferente de rigor na verificação de tipos, permitindo que os desenvolvedores escolham o nível de verificação mais adequado para seu projeto.
Neste artigo, exploraremos em detalhes cada um dos modos de verificação de tipos, abordando suas características, como configurar cada um deles e como eles podem beneficiar o desenvolvimento de aplicativos Angular mais seguros e eficientes.
Modos de Verificação de Tipos: Ajustando a Sensibilidade do Radar
O Angular oferece três modos de Template Type Checking, cada um com um nível de rigor diferente:
- Modo Básico: Realiza verificações básicas de tipo, como a existência de propriedades e a compatibilidade de tipos em expressões simples.
- Modo Completo: Realiza verificações mais completas, incluindo a análise de tipos em pipes, diretivas e outros elementos complexos dos seus templates.
- Modo Estrito: Aplica as verificações mais rigorosas, incluindo a verificação de nulos e a análise de tipos em todos os contextos do template.
Modo Básico de Verificação de Tipos: Um Primeiro Vistoria na Nave
No modo básico de verificação de tipos, com a flag fullTemplateTypeCheck
definida como false
, o Angular CLI realiza apenas verificações superficiais em seus templates, como um engenheiro espacial que faz uma inspeção visual rápida antes do lançamento.
Verificações Realizadas no Modo Básico
Nesse modo, o Angular CLI valida apenas as expressões de nível superior em um template.
Por exemplo, se você escrever <map [city]="user.address.city">
, o compilador verificará se:
user
é uma propriedade da classe do componente.user
é um objeto com uma propriedadeaddress
.user.address
é um objeto com uma propriedadecity
.
Limitações do Modo Básico: Zonas Cegas na Inspeção
Apesar de útil para identificar erros básicos, o modo básico possui algumas limitações importantes:
- Não verifica visualizações embutidas: O compilador não verifica os tipos dentro de visualizações embutidas, como
*ngIf
,*ngFor
e outros elementos<ng-template>
. - Não infere tipos complexos: O compilador não consegue determinar os tipos de
#refs
(referências a elementos do template), resultados de pipes ou o tipo de$event
em bindings de eventos. - Uso do tipo
any
: Em muitos casos, esses elementos acabam sendo tipados comoany
, o que pode fazer com que partes subsequentes da expressão não sejam verificadas.
Imagine que o modo básico de verificação de tipos é como uma inspeção visual da sua nave espacial. O engenheiro verifica se os painéis estão no lugar, se as luzes estão acesas e se os motores estão funcionando, mas não se aprofunda na análise de cada sistema e componente interno. Essa inspeção é útil para identificar problemas óbvios, mas pode não detectar falhas mais sutis ou complexas.
Quando Utilizar o Modo Básico
O modo básico é adequado para projetos menores ou em estágios iniciais de desenvolvimento, onde a prioridade é a rapidez na construção e a identificação de erros básicos. No entanto, para projetos maiores e mais complexos, ou para garantir um nível mais alto de segurança e confiabilidade, é recomendável utilizar o modo completo ou estrito de verificação de tipos.
Modo Completo de Verificação de Tipos: Uma Inspeção Mais Detalhada da Nave
No modo completo de verificação de tipos, com a flag fullTemplateTypeCheck
definida como true
, o Angular CLI se torna mais rigoroso na análise dos seus templates, como um engenheiro espacial que realiza uma inspeção detalhada de cada sistema e componente da nave antes do lançamento.
Verificações Realizadas no Modo Completo
Nesse modo, o Angular CLI vai além das verificações básicas, realizando uma análise mais profunda dos seus templates:
- Verifica visualizações embutidas: O compilador agora verifica os tipos dentro de visualizações embutidas, como
*ngIf
,*ngFor
e outros elementos<ng-template>
, garantindo que as expressões e bindings dentro dessas estruturas estejam corretas. - Verifica o tipo de retorno dos pipes: O compilador garante que o tipo de retorno dos pipes seja compatível com o contexto em que eles são utilizados.
- Verifica o tipo de referências locais: O compilador verifica se as referências locais a diretivas e pipes possuem o tipo correto, exceto para parâmetros genéricos, que ainda serão tipados como
any
.
Limitações do Modo Completo: Algumas Zonas Ainda Permanecem
Apesar de ser mais completo que o modo básico, o modo completo ainda possui algumas limitações:
- Referências a elementos DOM: Referências locais a elementos DOM continuam sendo tipadas como
any
. - Objeto
$event
: O objeto$event
em bindings de eventos também continua sendo tipado comoany
. - Expressões de navegação segura: Expressões que utilizam o operador de navegação segura (
?.
) para acessar propriedades de objetos potencialmente nulos ainda podem ter partes tipadas comoany
.
Importante: A Depreciação do fullTemplateTypeCheck
A flag fullTemplateTypeCheck
foi depreciada no Angular 13. Em seu lugar, você deve utilizar a família de opções de compilador strictTemplates
, que oferece um controle mais granular sobre a verificação de tipos em seus templates.
Analogia com a Inspeção da Nave
Imagine que o modo completo de verificação de tipos é como uma inspeção detalhada da sua nave espacial. O engenheiro não apenas verifica os aspectos externos, mas também se aprofunda na análise de cada sistema e componente interno, garantindo que tudo esteja funcionando corretamente e que não haja falhas ocultas.
Quando Utilizar o Modo Completo
O modo completo é recomendado para a maioria dos projetos Angular, pois oferece um bom equilíbrio entre segurança e desempenho. Ele detecta a maioria dos erros de tipo em seus templates, sem comprometer significativamente o tempo de compilação.
No entanto, se você precisa de um controle ainda mais rigoroso sobre os tipos em seus templates, ou se está trabalhando em um projeto crítico onde a segurança é primordial, o modo estrito pode ser a melhor opção.
Modo Estrito de Verificação de Tipos: Inspeção Minuciosa para uma Viagem Segura
No modo estrito de verificação de tipos, o Angular CLI se torna um inspetor implacável, examinando cada detalhe dos seus templates com o rigor de um engenheiro espacial preparando uma nave para uma missão crítica. Esse modo, acessado ao definir a flag strictTemplates
como true
, garante a máxima segurança e confiabilidade na sua aplicação Angular.
O Que o Modo Estrito Faz?
Além de todas as verificações realizadas no modo completo, o modo estrito adiciona ainda mais rigor à análise dos seus templates:
- Verifica bindings de componentes e diretivas: O compilador garante que os valores passados para os bindings de componentes e diretivas sejam compatíveis com os tipos definidos em seus
@Inputs
. - Respeita a flag
strictNullChecks
do TypeScript: O compilador aplica as regras de verificação de nulos do TypeScript, garantindo que você não acesse propriedades de objetos potencialmente nulos sem a devida verificação. - Infere tipos de componentes e diretivas: O compilador infere corretamente os tipos de componentes e diretivas, incluindo seus parâmetros genéricos, permitindo uma verificação de tipos mais precisa.
- Infere tipos de contexto de template: Em alguns casos, o compilador pode inferir os tipos de contexto de template, como em um
*ngFor
, permitindo uma verificação de tipos mais completa. - Infere o tipo de
$event
: O compilador infere corretamente o tipo do objeto$event
em bindings de eventos de componentes, diretivas, elementos DOM e animações. - Infere o tipo de referências a elementos DOM: O compilador infere o tipo correto de referências locais a elementos DOM, com base na tag do elemento, proporcionando uma experiência de desenvolvimento mais segura e previsível.
Analogia com a Inspeção da Nave
Imagine que o modo estrito de verificação de tipos é como uma inspeção minuciosa da sua nave espacial antes de uma missão crítica. O engenheiro não apenas verifica cada sistema e componente, mas também realiza testes rigorosos, simulações e análises detalhadas para garantir que a nave esteja em perfeitas condições para enfrentar os desafios da viagem.
Quando Utilizar o Modo Estrito
O modo estrito é recomendado para projetos Angular que exigem o mais alto nível de segurança e confiabilidade, como aplicações críticas ou de grande porte. Ele garante que seus templates estejam livres de erros de tipo, mesmo em cenários complexos, proporcionando uma experiência de desenvolvimento mais segura e previsível.
No entanto, é importante lembrar que o modo estrito pode aumentar o tempo de compilação e gerar mais avisos e erros, especialmente em projetos que não utilizam tipagem forte em todos os seus componentes. Por isso, é importante avaliar as necessidades do seu projeto e escolher o modo de verificação de tipos mais adequado.
erificação de Tipos em *ngFor
: Uma Análise Mais Profunda das Estruturas Repetitivas
No universo Angular, o *ngFor
é uma ferramenta poderosa para criar listas e exibir dados de forma dinâmica. No entanto, a verificação de tipos em estruturas repetitivas como o *ngFor
pode ser um desafio, especialmente em modos de verificação menos rigorosos.
O Impacto dos Modos de Verificação
Vamos considerar o seguinte exemplo, onde temos uma interface User
e um template que utiliza o *ngFor
para exibir informações dos usuários:
interface User {
name: string;
address: {
city: string;
state: string;
}
}
<div *ngFor="let user of users">
<h2>{{config.title}}</h2>
<span>Cidade: {{user.address.city}}</span>
</div>
O comportamento da verificação de tipos varia de acordo com o modo selecionado:
- Modo Básico: O Angular não verifica os tipos dentro da visualização embutida do
*ngFor
, ou seja, as expressõesconfig.title
euser.address.city
não são verificadas. - Modo Completo: O Angular verifica se
config
euser
existem, mas assume que ambos têm o tipoany
. Isso significa que o compilador não consegue garantir queconfig
possui uma propriedadetitle
ou queuser.address
possui uma propriedadecity
. - Modo Estrito: O Angular infere corretamente que a variável
user
dentro do*ngFor
tem o tipoUser
. Com essa informação, o compilador pode verificar seuser.address
é um objeto com uma propriedadecity
do tipostring
, garantindo a segurança e a consistência do seu código.
A Importância da Tipagem Forte
O exemplo acima demonstra a importância de utilizar tipagem forte em seus componentes e modelos de dados. Ao definir interfaces e tipos para suas variáveis, você permite que o Angular CLI realize verificações de tipo mais precisas, identificando potenciais erros em tempo de compilação e evitando problemas em tempo de execução.
A verificação de tipos em estruturas repetitivas como o *ngFor
é um recurso poderoso do Angular CLI, que garante a segurança e a consistência do seu código. Ao escolher o modo de verificação adequado e utilizar tipagem forte, você estará construindo aplicações Angular mais robustas e confiáveis.
Resolvendo Erros de Template: Dominando a Arte da Depuração no Angular
Introdução
À medida que você adota o modo estrito do Angular para verificação de tipos em templates, é provável que você encontre erros que não surgiram nos modos anteriores. Esses erros geralmente representam inconsistências genuínas de tipos nos templates que passaram despercebidas pelas ferramentas anteriores.
Embora essas mensagens de erro ajudem a identificar problemas reais, elas também podem sinalizar falsos positivos. Isso acontece quando as definições de tipos de uma biblioteca Angular são incompletas ou incorretas, ou quando as definições de tipos não correspondem completamente às expectativas. Vamos explorar essas situações e as soluções disponíveis.
Compreendendo Erros Comuns
- Definições de Tipos Incompletas ou IncorretasAlgumas bibliotecas podem não ter sido escritas considerando o
strictNullChecks
do TypeScript. Isso pode resultar em definições de tipos que não levam em contanull
ouundefined
.Exemplo: A tipagem de uma biblioteca pode não incluirnull | undefined
, resultando em erros de verificação de tipo ao trabalhar em modo estrito. - Tipos de Entrada Muito RestritosQuando as definições de tipos de entrada de uma biblioteca são excessivamente restritivas, o Angular pode não conseguir determinar o tipo correto. Isso é comum em atributos Boolean, como
disabled
.Exemplo: Atributos como<input disabled>
podem não ser corretamente interpretados como Boolean se a biblioteca não tiver adicionado os metadados apropriados. - Uso do
$event.target
em Eventos DOMDevido à possibilidade de propagação de eventos (event bubbling),$event.target
nas definições de tipos do DOM pode não ter o tipo que você esperaria.Exemplo: Ao usar$event.target
, o tipo pode não corresponder ao elemento esperado devido à natureza dinâmica dos eventos DOM.
Resolvendo Erros de Template: Dominando a Arte da Depuração no Angular
Introdução
À medida que você adota o modo estrito do Angular para verificação de tipos em templates, é provável que você encontre erros que não surgiram nos modos anteriores. Esses erros geralmente representam inconsistências genuínas de tipos nos templates que passaram despercebidas pelas ferramentas anteriores.
Embora essas mensagens de erro ajudem a identificar problemas reais, elas também podem sinalizar falsos positivos. Isso acontece quando as definições de tipos de uma biblioteca Angular são incompletas ou incorretas, ou quando as definições de tipos não correspondem completamente às expectativas. Vamos explorar essas situações e as soluções disponíveis.
Compreendendo Erros Comuns
- Definições de Tipos Incompletas ou IncorretasAlgumas bibliotecas podem não ter sido escritas considerando o
strictNullChecks
do TypeScript. Isso pode resultar em definições de tipos que não levam em contanull
ouundefined
.Exemplo: A tipagem de uma biblioteca pode não incluirnull | undefined
, resultando em erros de verificação de tipo ao trabalhar em modo estrito. - Tipos de Entrada Muito RestritosQuando as definições de tipos de entrada de uma biblioteca são excessivamente restritivas, o Angular pode não conseguir determinar o tipo correto. Isso é comum em atributos Boolean, como
disabled
.Exemplo: Atributos como<input disabled>
podem não ser corretamente interpretados como Boolean se a biblioteca não tiver adicionado os metadados apropriados. - Uso do
$event.target
em Eventos DOMDevido à possibilidade de propagação de eventos (event bubbling),$event.target
nas definições de tipos do DOM pode não ter o tipo que você esperaria.Exemplo: Ao usar$event.target
, o tipo pode não corresponder ao elemento esperado devido à natureza dinâmica dos eventos DOM.
Soluções para Falsos Positivos
Quando enfrentar falsos positivos, considere as seguintes soluções:
- Usar
$any()
para Ignorar Verificações de TipoO$any()
permite que você desative a verificação de tipos para partes específicas de uma expressão.
<div>{{ $any(user).address.city }}</div>
2. Desativar Verificações Estritas
Se necessário, você pode desativar completamente as verificações estritas definindo strictTemplates: false
no arquivo de configuração TypeScript da sua aplicação, tsconfig.json
.
3. Ajustar Flags de Estricção Individualmente
Você pode desativar operações específicas de verificação de tipos enquanto mantém a estricção em outros aspectos, configurando uma flag de estricção para false
.
{
"angularCompilerOptions": {
"strictTemplates": true,
"strictInputTypes": false
}
}
Flags de Estricção e Seus Efeitos
Cada flag de estricção oferece um controle refinado sobre como o Angular verifica tipos nos templates:
strictInputTypes
: Verifica se a expressão de ligação é atribuível ao campo@Input()
. Também afeta a inferência de tipos genéricos de diretivas.strictInputAccessModifiers
: Considera modificadores de acesso comoprivate
ouprotected
ao verificar ligações@Input()
. Este éfalse
por padrão.strictNullInputTypes
: HonrastrictNullChecks
ao verificar ligações@Input()
. Útil para bibliotecas que não foram criadas comstrictNullChecks
.strictAttributeTypes
: Verifica ligações@Input()
feitas usando atributos de texto, como<input disabled="true">
.strictSafeNavigationTypes
: Infere corretamente o tipo de operações de navegação segura, comouser?.name
.strictDomLocalRefTypes
: Define se referências locais a elementos DOM terão o tipo correto.strictOutputEventTypes
: Verifica se$event
tem o tipo correto para ligações de evento em componentes/diretivas e eventos de animação.strictDomEventTypes
: Verifica se$event
tem o tipo correto para eventos DOM.strictContextGenerics
: Infere corretamente os parâmetros de tipo de componentes genéricos.strictLiteralTypes
: Infere o tipo de literais de objeto e array declarados no template.
Se as Soluções Não Funcionarem
Se ainda enfrentar problemas após ajustar essas flags, considere as seguintes abordagens:
- Retornar ao Modo CompletoDesative o
strictTemplates
e volte ao modo completo definindofullTemplateTypeCheck: false
. - Desativar o Modo CompletoComo último recurso, desative o modo completo para retornar ao modo básico.
Reportando Bugs
Se encontrar um erro de verificação de tipos que não pode ser resolvido com os métodos recomendados, pode ser um bug no verificador de tipos de templates do Angular. Se isso acontecer, é recomendável abrir uma issue para que a equipe possa investigá-lo e corrigi-lo.
Inputs e Verificação de Tipos: Garantindo a Compatibilidade dos Dados na sua Nave Espacial
No universo Angular, a comunicação entre componentes é essencial para o funcionamento harmonioso da sua aplicação. Os inputs, como cabos de conexão entre módulos da sua nave espacial, permitem que você passe dados de um componente pai para um componente filho. O Template Type Checking entra em cena para garantir que esses dados sejam compatíveis e seguros, evitando falhas na comunicação e garantindo a integridade da sua nave.
Verificando a Compatibilidade de Tipos: O Radar em Ação
O verificador de tipos de template checa se o tipo de uma expressão de binding é compatível com o tipo do input correspondente na diretiva.
Exemplo: Componente UserDetail
Considere o seguinte exemplo de um componente UserDetail
que exibe detalhes de um usuário:
// user-detail.component.ts
export interface User {
name: string;
}
@Component({
selector: 'app-user-detail',
template: '{{ user.name }}',
})
export class UserDetailComponent {
@Input() user: User;
}
Neste componente, a propriedade user
é um @Input()
que espera um objeto do tipo User
.
Uso do Componente no AppComponent
Agora, veja como o AppComponent
utiliza o componente UserDetail
:
@Component({
selector: 'app-root',
template: '<user-detail [user]="selectedUser"></user-detail>',
})
export class AppComponent {
selectedUser: User | null = null;
}
Aqui, a propriedade selectedUser
do AppComponent
é do tipo User | null
.
Durante a verificação de tipos do template para AppComponent
, a ligação [user]="selectedUser"
corresponde à entrada user
do componente UserDetailComponent
.
TypeScript e as Flags de Compilador: O Manual de Segurança
O TypeScript é responsável por verificar a atribuição de acordo com seu sistema de tipos, respeitando as flags de compilador, como strictNullChecks
, configuradas na aplicação. No exemplo acima, se a flag strictNullChecks
estiver habilitada, o compilador irá gerar um erro, pois selectedUser
pode ser null
, enquanto o input user
do UserDetailComponent
espera um objeto do tipo User
.
Evitando Erros em Tempo de Execução: Reforçando a Segurança
Para evitar erros em tempo de execução, é crucial fornecer requisitos de tipo mais específicos no template para o verificador de tipos. Ao criar suas próprias diretivas, defina os tipos de entrada (@Input
) da forma mais precisa possível, utilizando funções de guarda de template (template-guard functions
) na definição da diretiva. Consulte a seção “Melhorando a verificação de tipo para diretivas personalizadas” neste guia para obter mais informações.
Verificações Estritas de Nulidade: Navegando com Segurança em Terrenos Acidentados
Ao habilitar o modo estrito de verificação de tipos (strictTemplates
) em conjunto com a flag strictNullChecks
do TypeScript, você garante um nível máximo de segurança em seus templates Angular. No entanto, essa combinação poderosa pode levar a erros de verificação de tipo em situações específicas que podem ser desafiadoras de evitar.
Cenários Problemáticos
Valor Nullable Vinculado a uma Diretiva de Biblioteca
Uma situação comum ocorre quando um valor nullable é vinculado a uma diretiva de uma biblioteca que não foi compilada com strictNullChecks
ativado. Para bibliotecas compiladas sem strictNullChecks
, seus arquivos de declaração não indicam se um campo pode ser null
ou não. Se a biblioteca manipula corretamente valores null
, isso se torna problemático, pois o compilador verifica um valor nullable contra os arquivos de declaração que omitem o tipo null
. Consequentemente, o compilador produz um erro de verificação de tipo devido à adesão ao strictNullChecks
.
Uso do async
Pipe com um Observable Sincrônico
Outro cenário envolve o uso do pipe async
com um Observable que você sabe que emitirá valores de forma sincrônica. O pipe async
assume que o Observable ao qual está inscrito pode ser assíncrono, o que significa que é possível que não haja valor disponível ainda, retornando assim null
. Em outras palavras, o tipo de retorno do pipe async
inclui null
, o que pode resultar em erros em situações onde o Observable é conhecido por emitir um valor não-nullable de forma síncrona.
Soluções para Erros de Nullidade
Para lidar com esses problemas, há duas soluções potenciais:
- Uso do Operador de Asserção de Não-Null (
!
)No template, inclua o operador de asserção de não-null (!
) no final de uma expressão nullable. Isso instrui o compilador a ignorar incompatibilidades de tipo relacionadas à nullidade, da mesma forma que no código TypeScript.
<user-detail [user]="user!"></user-detail>
No caso do pipe async
, a expressão precisa ser envolvida em parênteses:
<user-detail [user]="(user$ | async)!"></user-detail>
Aqui, o compilador desconsidera a possibilidade de null
, assumindo que o valor emitido pelo Observable não será null
.
2. Desativar Verificações Estritas de Null em Templates
Se o uso do operador de não-null não for viável, outra opção é desativar completamente as verificações estritas de null nos templates Angular. Ao ativar o strictTemplates
, ainda é possível desativar certos aspectos da verificação de tipo. Ajustando a opção strictNullInputTypes
para false
, você desativa as verificações estritas de null nos templates Angular. Essa flag se aplica a todos os componentes que fazem parte da aplicação.
{
"angularCompilerOptions": {
"strictTemplates": true,
"strictNullInputTypes": false
}
}
Escolhendo a Melhor Abordagem
A escolha da melhor abordagem depende das suas necessidades e do contexto do seu projeto. Se você está confiante de que o Observable emitirá um valor não nulo de forma síncrona ou se a biblioteca lida corretamente com valores nulos, o operador de asserção não nula !
pode ser uma solução rápida e eficaz.
No entanto, se você prefere evitar o uso de !
ou se está lidando com muitas situações onde a nulidade pode ser um problema, desabilitar strictNullInputTypes
pode ser uma opção mais segura e consistente.
Boas Práticas para Autores de Bibliotecas
Como autor de uma biblioteca Angular, você desempenha um papel crucial na jornada dos desenvolvedores que utilizam sua criação. Ao fornecer uma biblioteca bem estruturada, com tipagens claras e precisas, você facilita a vida dos seus usuários e garante uma experiência de desenvolvimento mais segura e produtiva.
Coerção de Setters de Entrada: Flexibilidade e Segurança na Comunicação entre Componentes
Em algumas situações, é desejável que o @Input
de uma diretiva ou componente altere o valor vinculado a ele, geralmente usando um par getter/setter para o input. Essa flexibilidade, no entanto, pode levar a desafios na verificação de tipos, especialmente quando o modo estrito está habilitado.
O Desafio da Coerção de Tipos
Imagine um componente de botão personalizado que possui um input disabled
do tipo booleano:
@Component({
selector: 'submit-button',
template: `
<div class="wrapper">
<button [disabled]="disabled">Submit</button>
</div>
`,
})
class SubmitButton {
private _disabled: boolean;
@Input()
get disabled(): boolean {
return this._disabled;
}
set disabled(value: boolean) {
this._disabled = value;
}
}
No exemplo acima, o input disabled
do componente é passado para o botão <button>
no template. Tudo isso funciona conforme o esperado, desde que um valor booleano seja vinculado ao input.
Problema com Atributos no Template
No entanto, imagine que um consumidor use esse input no template como um atributo:
<submit-button disabled></submit-button>
Isso tem o mesmo efeito que a seguinte ligação:
<submit-button [disabled]="''"></submit-button>
No tempo de execução, o input será configurado como uma string vazia, o que não é um valor booleano. Bibliotecas de componentes Angular que lidam com esse problema muitas vezes “coagem” o valor para o tipo correto no setter:
set disabled(value: boolean) {
this._disabled = (value === '') || value;
}
Aqui, o setter disabled
aceita o valor e o transforma em um booleano, considerando que uma string vazia deve ser tratada como true
.
Tipo de Aceitação de Input com ngAcceptInputType_
Idealmente, seria ideal mudar o tipo de value
no setter de boolean
para boolean|''
, para coincidir com o conjunto de valores que realmente são aceitos pelo setter. No entanto, até a versão 4.3 do TypeScript, tanto o getter quanto o setter precisavam ter o mesmo tipo, então, se o getter retornar um boolean
, o setter também precisaria usar esse tipo mais restrito.
Com a verificação de tipos mais estrita do Angular para templates habilitada, isso cria um problema: a string vazia (''
) não é atribuível ao campo disabled
, o que gera um erro de tipo quando o formulário de atributo é usado.
Solução com ngAcceptInputType_
Para contornar esse problema, o Angular suporta a verificação de um tipo mais amplo e permissivo para @Input()
do que o declarado para o campo de input. Isso pode ser habilitado adicionando uma propriedade estática com o prefixo ngAcceptInputType_
à classe do componente:
class SubmitButton {
private _disabled: boolean;
@Input()
get disabled(): boolean {
return this._disabled;
}
set disabled(value: boolean) {
this._disabled = (value === '') || value;
}
static ngAcceptInputType_disabled: boolean | '';
}
Como Funciona
A existência dessa propriedade estática comunica ao verificador de tipos do Angular que o input disabled
deve ser considerado como aceitando ligações que correspondem ao tipo boolean|''
. O sufixo deve ser o nome do campo @Input
.
No TypeScript 4.3, o setter poderia ser declarado para aceitar boolean|''
como tipo, tornando o campo de coerção do setter de input obsoleto. Portanto, campos de coerção de setters de input foram depreciados. Contudo, em versões anteriores ou situações em que a mudança não é possível, o uso do ngAcceptInputType_
ainda é relevante.
Cuidado com a Coerção de Input
Deve-se ter cuidado para garantir que, se uma substituição ngAcceptInputType_
estiver presente para um dado input, então o setter deve ser capaz de lidar com quaisquer valores do tipo sobrescrito.
Desativando a Verificação de Tipos com $any()
: A Saída de Emergência
Quando a verificação de tipos em templates Angular está ativada, ela pode ocasionalmente sinalizar erros que você sabe que são falsos positivos ou que você deseja suprimir temporariamente por algum motivo. Em tais casos, o Angular oferece a pseudo-função $any()
para desativar a verificação de tipos em expressões específicas.
Como Funciona o $any()
A pseudo-função $any()
funciona como um operador de coerção, convertendo a expressão em um tipo any
, similar ao que fazemos em TypeScript quando usamos as palavras-chave <any>
ou as any
para conversões explícitas de tipo. Isso informa ao compilador que ele deve tratar a expressão como any
, ignorando as verificações de tipo normais.
Exemplo de Uso
Considere um componente onde temos um objeto person
que pode ou não ter uma propriedade address
. Sem a coerção para any
, a verificação de tipos mais rígida do Angular pode sinalizar um erro se address
não existir ou não for garantido pelo tipo definido.
Aqui está como você pode usar $any()
para evitar esse tipo de erro:
@Component({
selector: 'my-component',
template: '{{$any(person).address.street}}'
})
class MyComponent {
person?: Person;
}
No exemplo acima, estamos usando $any(person)
para suprimir o erro de tipo que pode surgir se address
não for uma propriedade da interface Person
. O compilador não verificará mais se person
tem uma propriedade address
, evitando assim erros de tipo.
Quando Usar $any()
- Supressão de Erros Temporários: Útil durante o desenvolvimento, quando você está ciente de que um determinado trecho de código pode causar erros de tipo, mas ainda está em progresso ou será revisado posteriormente.
- Falsos Positivos: Em situações em que a verificação de tipo do Angular sinaliza um erro que você tem certeza ser incorreto, e você deseja contornar esse erro sem alterar a lógica subjacente.
- Bibliotecas Externas: Ao integrar bibliotecas que não foram escritas com verificações de tipo rígidas ou que apresentam tipagens incompletas, o uso de
$any()
pode ajudar a lidar com tais casos até que a biblioteca seja atualizada ou uma solução melhor seja encontrada.
Considerações
Embora $any()
ofereça um meio conveniente de ignorar a verificação de tipos em situações específicas, ele deve ser usado com cautela. Dependendo muito de $any()
pode reduzir a robustez do seu código, pois você perde as garantias de tipo que o TypeScript e o Angular proporcionam.
- Documente o Uso: Sempre que utilizar
$any()
, documente a razão em um comentário para que outros desenvolvedores (ou você no futuro) entendam por que a verificação de tipos foi suprimida. - Refatoração Posterior: Planeje refatorar o uso de
$any()
sempre que possível, buscando resolver a causa subjacente do erro de tipo ou atualizar as definições de tipo para melhor refletir o seu modelo de dados.
O $any()
é uma ferramenta poderosa no arsenal do desenvolvedor Angular para lidar com verificações de tipo em templates, mas deve ser usado com moderação e sempre com a intenção de melhorar o código em iterações futuras.
Conclusão
Lembre-se, o Template Type Checking é como um radar que detecta falhas em sua nave espacial Angular. Ao utilizá-lo com sabedoria e seguir as boas práticas, você garante uma viagem tranquila e livre de surpresas pelo universo da web.
A jornada não termina aqui! Continue explorando o Angular CLI e descubra todas as suas funcionalidades e recursos para construir aplicações web incríveis.