Na parte anterior desta série de postagens, discutimos sobre nulidade segura.
Agora vamos explicar e resolver o terceiro e último problema do comportamento padrão do TypeScript: restos de digitação dinâmica.
Abordaremos:
TypeScript deve ser um "verificador de tipo estático", ao contrário do JavaScript, no qual a digitação é profundamente dinâmica.
Mas em uma parte anterior desta série de postagens, também explicamos que TypeScript é construído como um superconjunto de JavaScript.
Portanto, o problema é: algumas partes do sistema de digitação dinâmica JavaScript permanecem no TypeScript. Portanto, vamos explicar como suprimir esses comportamentos restantes para obter digitação estática completa.
O melhor exemplo do problema são as verificações de igualdade. Em JavaScript, == não é exatamente uma verificação de igualdade, mas uma verificação de equivalência:
1 == "1"; // true
Apesar dos tipos serem diferentes, algumas regras de conversão entram em ação para que o JavaScript consiga comparar os valores. Isso pode levar a muitos erros, porque os detalhes das regras são difíceis de lembrar, às vezes são bastante estranhos e não são exatamente os mesmos em todas as linguagens dinâmicas (como PHP, por exemplo).
Essas verificações de equivalência só fazem sentido em uma linguagem de tipo dinâmico como JavaScript. A partir do momento em que decidimos trabalhar em TypeScript, apenas verificações reais de igualdade (tipo e valor) devem ser usadas.
1 === "1"; // false
A regra eqeqeq lint aplica isso.
Pessoas provenientes de linguagens como Java, C# ou Rust devem ter cuidado especial com esse problema, pois == em JavaScript ou TypeScript não significa o mesmo que nessas linguagens. Em JavaScript e TypeScript, um terceiro = é necessário para obter o mesmo comportamento.
Acha que as condições agora são seguras? Infelizmente não, porque as conversões podem ser implícitas:
let tax: number | undefined = 0; if (tax) { console.log("Process payment"); } if (!tax) { throw new Error(); }
O exemplo acima é equivalente a:
let tax: number | undefined = 0; if (tax == true) { console.log("Process payment"); } if (tax == false) { throw new Error(); }
Como você pode ver, havia == implícito, então as conversões ainda acontecem: 0 não é equivalente a verdadeiro, é equivalente a falso. Portanto, ocorrerá um erro, apesar do imposto ser um valor válido.
A regra lint de expressões booleanas estritas não permite tais condições implícitas e impõe verificações reais:
let tax: number | undefined = 0; if (tax !== undefined) { console.log("Process payment"); } if (tax === undefined) { throw new Error(); }
Pode ser uma das regras mais tediosas a seguir para pessoas acostumadas com condições rápidas em JavaScript, mas para colocar isso em perspectiva, é apenas a maneira normal de fazer coisas em outras linguagens como Java, C# ou Rust.
Conforme mostrado na parte de configuração, desabilitar as subopções permitirNumber e permitirString é importante para evitar todos os erros.
A única exceção permitida é para objetos e arrays: esses casos são seguros porque, ao contrário de strings e números, eles não possuem valores falsos. Portanto, o seguinte ainda está OK:
let movie: Movie | undefined; if (movie) {} if (!movie) {}
Nota: as instruções switch já são seguras, pois usam === internamente.
A regra lint de expressões booleanas estritas cuida para que as verificações de condições sejam de tipo seguro, mas existem outras sintaxes de condições além de if:
const movieRating = userRating || 5; // Which is a shorter version of: const movieRating = userRating == true ? userRating : 5;
Se o usuário avaliou 0, 0 é equivalente a falso, então a classificação será 5 em vez de 0.
Isso pode ser evitado com JavaScript moderno:
const movieRating = userRating ?? 5; // Which is a shorter version of: const movieRating = userRating !== undefined && userRating !== null ? userRating : 5;
Isso pode ser aplicado pela regra de lint preferencial-nulo-coalescente.
Observe que ?? não deve ser usado em todos os lugares: || ainda é relevante ao trabalhar com booleanos.
Em JavaScript, o operador pode ser usado tanto para adição matemática de números quanto para concatenação de strings. Isso leva ao erro.
"There is " 3 1 "Matrix movies"; // 31 "There is " (3 1) "Matrix movies"; // 4
O operador deve ser reservado para adição matemática. Ou, pelo menos, deve ser usado apenas com dados do mesmo tipo, que a regra lint de restrição mais operandos impõe.
As strings de modelo do JavaScript moderno devem ser usadas para concatenação de strings, o que a regra lint de modelo preferido impõe:
const movie = `Everything everywhere all at once`; `${movie} is the best movie!`;
Por outro lado, apenas strings devem ser usadas em strings de modelo, o que a regra lint de expressões de modelo restrito impõe.
Se misturar tipos é o que realmente se deseja, as conversões devem ser explícitas:
const total = 3; `There is ${total.toFixed()} Matrix movies`;
Observe que as strings do modelo podem ser aninhadas:
const total = 3; `There is ${total.toFixed()} Matrix movie${total > 1 ? "s" : ""}`;
Este é o fim desta série de posts. Você pode seguir minha conta (botão no canto superior direito desta página) para saber quando outros posts sobre TypeScript ou outros tópicos como Angular forem publicados.
Você quer entrar em contato comigo? As instruções estão disponíveis no resumo.
Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.
Copyright© 2022 湘ICP备2022001581号-3