O strict são oito opções, e as que ele não liga
O strict: true não é uma opção. São oito, ligadas de uma vez, e tratá-las como um interruptor só é a razão por que tanta gente não consegue ligá-lo num projeto que já existe.
Também não é o fim da linha: há meia dúzia de verificações que o strict não liga, e é lá que estão os erros que sobram depois de ele estar ligado.
1. O que o strict liga
noImplicitAny— um parâmetro sem tipo deixa de seranyem silêncio.strictNullChecks— esta é a que encontra erros a sério, e a que dá mais trabalho:nulleundefineddeixam de caber em todos os tipos.useUnknownInCatchVariables— o que se apanha numcatchpassa aunknown, porque o que é atirado pode ser qualquer coisa e não umError.strictFunctionTypes,strictBindCallApply,strictPropertyInitialization,noImplicitThis,alwaysStrict— as restantes, que quase nunca dão luta.
Na prática, ligar o strict num projeto antigo é ligar o strictNullChecks. As outras sete resolvem-se numa tarde.
2. Por onde começar quando não compila
A tentação é pôr strict: false e ir ligando uma a uma. Funciona, e há uma forma melhor:
{
"strict": true,
"strictNullChecks": false
}A diferença não é técnica, é de legibilidade. Com strict: false, o ficheiro não diz o que falta — diz só que se desistiu. Assim, a lista de exceções está à vista e encolhe, e no dia em que a última sai o ficheiro fica com uma linha em vez de nove.
3. As opções que o strict não liga
E a primeira é a que vale o artigo:
const primeiro = lista[0];
// ^? com strict: string
// ^? com noUncheckedIndexedAccess: string | undefinedCom o strict sozinho, aquele lista[0] tem tipo string — numa lista vazia. É uma mentira que o modo estrito autoriza, e é a origem de uma boa parte dos «cannot read properties of undefined» que ainda aparecem em código inteiramente tipado.
O noUncheckedIndexedAccess corrige isso, e é também o que faz mais barulho: passa a assinalar todos os acessos por índice, incluindo os que nunca falharam. A compensação é que o compilador passa a obrigar ao que os type guards já faziam à mão.
As outras que valem a pena:
noFallthroughCasesInSwitch— obreakesquecido. Barato, zero ruído.noImplicitOverride— obriga a escreveroverride, e apanha o método que deixou de sobrepor nada porque alguém renomeou o da classe-mãe.exactOptionalPropertyTypes— distingue «a propriedade não existe» de «existe e valeundefined». Correcto, e o que custa mais a adoptar.noUnusedLocalsenoUnusedParameters— discutíveis no compilador, porque o ESLint já os dá sem travar o build.
4. O skipLibCheck, que está em quase todos os projetos
Está neste, e está no template de que quase todos partem. O que ele faz é não verificar os ficheiros de declaração das dependências — e a razão de existir é boa: um erro de tipos dentro de uma biblioteca de terceiros não é um erro que se possa corrigir, e sem ele um projeto grande pára por causa de dois pacotes em desacordo.
O preço é saber que é um ponto cego: tipos de bibliotecas incompatíveis entre si deixam de ser assinalados. É uma troca razoável, e é diferente de não saber que se fez a troca.
5. A ordem que eu seguiria
Pela relação entre o que apanham e o que incomodam: noFallthroughCasesInSwitch e noImplicitOverride primeiro, que entram quase sem alterações. Depois noUncheckedIndexedAccess, que é o que encontra bugs reais e exige uma passagem pelo código. O exactOptionalPropertyTypes em último, ou nunca.
Neste site o strict está ligado e nenhuma das outras está. Não é descuido: é um piso assumido, e o noUncheckedIndexedAccess é o próximo candidato — com a expectativa realista de que assinale algumas dezenas de sítios, a maioria deles inofensivos.
O resumo
O strict são oito opções, e ligá-lo é essencialmente ligar o strictNullChecks. Mantenha-se strict: true com exceções à vista, em vez de strict: false. E se houver uma única a acrescentar depois, é o noUncheckedIndexedAccess: é a diferença entre ter tipos e acreditar neles.