← TypeScript: tipos, contratos e diagnóstico
01 / 10 · 50 MIN

Tipos estáticos e valores em execução

Separa verificação estática, transformação e valores reais; usa inferência e unknown sem confundir tipos com validação de dados.

Três perguntas diferentes sobre o mesmo programa

A análise de um excerto começa por separar três perguntas: o verificador aceita o programa, a ferramenta produz um artefacto e o valor recebido satisfaz o contrato real? Uma resposta positiva à primeira não responde automaticamente às outras. Uma anotação number permite detetar utilizações incompatíveis conhecidas durante a verificação, mas não acrescenta uma guarda a todos os chamadores externos.

O percurso adota TypeScript 7.0 e indica explicitamente strict: true. Não depende de valores predefinidos do compilador. O JavaScript continua a definir o comportamento dos valores; React e Angular pertencem aos seus percursos. Todas as avaliações usam escolhas sobre código e cenários, sem pedir execução.

Inferência conserva um contrato

Em let attempts = 4, o inicializador dá informação suficiente para inferir number. A ausência de uma anotação escrita não implica any. Atribuir depois "4" contradiz esse contrato; o verificador não introduz uma conversão para tornar a atribuição válida.

Também é necessário distinguir um binding const das propriedades do objeto para o qual aponta. const request = { mode: "read" } permite que a propriedade receba outro texto. Por isso, a propriedade pode ser inferida como string, mais ampla do que uma união de literais. Um tipo explícito ou uma preservação intencional do literal pode expressar o contrato; não se deve acrescentar uma assertion apenas para silenciar uma chamada.

unknown mantém a pergunta em aberto

Dados externos ainda não inspecionados devem conservar a incerteza. unknown pode receber qualquer valor, mas não permite usar diretamente métodos ou propriedades como se a forma já estivesse demonstrada. Uma condição typeof, uma verificação de ausência ou um validador pode fornecer a informação em falta.

any permite muitos acessos sem essa evidência e pode espalhar suposições não verificadas pelos consumidores. Nem unknown nem any executam uma validação. A vantagem de unknown é exigir que o programa enfrente a fronteira antes da utilização. Uma assertion continua a poder contornar essa exigência; a revisão precisa de examinar o caminho dos dados, não apenas o nome do tipo.

Assertions não transformam valores

A expressão input as number afirma uma perspetiva estática. Não chama Number, não verifica dígitos e não escolhe um intervalo permitido. Se input contiver texto, o valor continua a ser texto depois de retirar a assertion do JavaScript produzido. Uma dupla assertion também não fornece evidência adicional sobre os dados.

O operador pós-fixo ! remove null e undefined da perspetiva estática naquele uso, mas não inventa um campo ausente. É preciso saber por que motivo a ausência é impossível. Quando os dados reais podem contrariar a suposição, uma decisão explícita de rejeição, ausência ou recuperação é mais informativa do que esconder o diagnóstico.

Ausência precisa de uma política própria

Com strictNullChecks ativo, string | null descreve duas possibilidades que precisam de tratamento antes de chamar um método de string. Uma saída antecipada quando o valor é null permite usar a string nos caminhos restantes. A mesma intenção pode ser expressa com um operador condicional que trata cada possibilidade.

Uma condição de veracidade não é automaticamente equivalente. Se a string vazia for um valor válido, if (name) deixa-a fora do ramo verdadeiro. A política do domínio deve decidir se vazio, ausente e inválido significam coisas diferentes. Mudar a configuração para remover o diagnóstico não altera nenhum desses valores nem corrige a política.

Leitura guiada de uma fronteira

No exemplo, raw é unknown porque a função não presume a origem correta do valor. Primeiro exige texto não vazio composto apenas por dígitos ASCII. Só depois converte e confirma que o número é inteiro e está no intervalo. A aceitação admite zeros iniciais: "007" representa a quantidade sete neste contrato, não um identificador cuja grafia deva ser preservada.

Prevê as decisões para "0", 0, "2.5", "501" e "007" sem executar o código. Se o fornecedor passar a enviar números diretamente, o contrato e a primeira verificação têm de mudar em conjunto. Substituir estas verificações por as number retiraria a validação de que a função depende.

Evidência de entrega sem confundir etapas

Uma verificação com noEmit pode ser um controlo útil antes de entregar código, mas não produz os ficheiros que outra etapa poderá exigir. É necessário identificar quem transforma TypeScript em JavaScript, quais artefactos entram na publicação e que configuração foi usada. Um relatório sem diagnósticos só descreve o âmbito efetivamente verificado.

Nos casos desta aula, a decisão começa nos dados e termina num contrato explícito para o consumidor. A revisão deve indicar qual suposição foi demonstrada e qual continua externa: formato da origem, transformação, intervalo, estrutura ou existência do artefacto. Não se deduz comportamento completo da aplicação a partir de uma anotação ou de uma compilação sem erros.

// TypeScript 7.0; strict: true; ES2022 library.
type QuantityResult =
  | { ok: true; value: number }
  | { ok: false; reason: "format" | "range" };

function readQuantity(raw: unknown): QuantityResult {
  if (typeof raw !== "string" || raw.length === 0 || /[^0-9]/.test(raw)) {
    return { ok: false, reason: "format" };
  }
  const value = Number(raw);
  if (!Number.isInteger(value) || value < 0 || value > 500) {
    return { ok: false, reason: "range" };
  }
  return { ok: true, value };
}
NA PRÁTICA

Lê o excerto com strict: true. O texto "0" é aceite; o Number 0 é rejeitado pelo formato acordado; "501" ultrapassa o intervalo. A função não modifica estado externo e nenhuma assertion substitui as verificações.

Armadilhas comuns

Tratar as number como conversão; confiar em ! para preencher campos; usar any para ocultar contratos incompletos; confundir noEmit com uma entrega pronta.

Tópicos relacionados: Uniões, refinamento de tipos e modelos de estado · Dados externos e fronteiras de erro · Configuração, entrega e migração

Leva esta ideia contigo

Um tipo descreve o que o programa assume. A fronteira precisa de verificar que os dados recebidos sustentam essa suposição.

Criar conta

Referência: TypeScript Handbook: The Basics · TypeScript 7.0; explicit strict and host configuration