Experts in Angular

Angular CLITemplate Type Checking no Angular CLI
Template type checking

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 propriedade address.
  • user.address é um objeto com uma propriedade city.

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 como any, 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 como any.
  • 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 como any.

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ões config.title e user.address.city não são verificadas.
  • Modo Completo: O Angular verifica se config e user existem, mas assume que ambos têm o tipo any. Isso significa que o compilador não consegue garantir que config possui uma propriedade title ou que user.address possui uma propriedade city.
  • Modo Estrito: O Angular infere corretamente que a variável user dentro do *ngFor tem o tipo User. Com essa informação, o compilador pode verificar se user.address é um objeto com uma propriedade city do tipo string, 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

  1. 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 conta null ou undefined.Exemplo: A tipagem de uma biblioteca pode não incluir null | undefined, resultando em erros de verificação de tipo ao trabalhar em modo estrito.
  2. 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.
  3. 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

  1. 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 conta null ou undefined.Exemplo: A tipagem de uma biblioteca pode não incluir null | undefined, resultando em erros de verificação de tipo ao trabalhar em modo estrito.
  2. 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.
  3. 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:

  1. 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 como private ou protected ao verificar ligações @Input(). Este é false por padrão.
  • strictNullInputTypes: Honra strictNullChecks ao verificar ligações @Input(). Útil para bibliotecas que não foram criadas com strictNullChecks.
  • 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, como user?.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:

  1. Retornar ao Modo CompletoDesative o strictTemplates e volte ao modo completo definindo fullTemplateTypeCheck: false.
  2. 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:

  1. 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.