Strict Mode no TypeScript: Como Ativar
Ative o strict mode no TypeScript e elimine categorias inteiras de bugs. Guia prático com cada flag explicada, exemplos reais e estratégia de adoção incremental.
O Que É o Strict Mode no TypeScript
O strict mode é uma flag do tsconfig.json que liga 8 verificações de segurança de uma vez. É como colocar o TypeScript no modo mais rigoroso possível. Cada flag pega uma categoria específica de bug.
Quando você adiciona "strict": true no compilerOptions, o TypeScript ativa: strictNullChecks, noImplicitAny, strictBindCallApply, strictFunctionTypes, strictPropertyInitialization, noImplicitThis, useUnknownInCatchVariables e alwaysStrict.
Dá pra ativar cada flag individualmente. Isso é útil pra adoção gradual em projetos existentes. Mas em projetos novos, vai de strict: true direto. Sem desculpa.
Como Ativar o Strict Mode Passo a Passo
Se o projeto é novo, ativa tudo de uma vez. Se já existe, vai aos poucos. Aqui vai a estratégia pra cada cenário.
Cada Flag Explicada com Exemplos
Vamos ver o que cada flag faz na prática. Código real mostra melhor que descrições abstratas.
strictNullChecks — A Flag Mais Impactante
// SEM strictNullChecks (perigoso)
function buscarUsuario(id: string): User {
// Pode retornar undefined, mas o tipo diz User
return database.find(u => u.id === id);
}
const user = buscarUsuario('123');
console.log(user.name); // Runtime error: Cannot read property 'name' of undefined
// COM strictNullChecks (seguro)
function buscarUsuario(id: string): User | undefined {
return database.find(u => u.id === id);
}
const user = buscarUsuario('123');
// console.log(user.name); // Erro de compilação!
// Jeito correto:
if (user) {
console.log(user.name); // OK - TypeScript sabe que não é undefined
}
// Ou com optional chaining:
console.log(user?.name ?? 'Usuário não encontrado');
Essa flag sozinha previne a maioria dos erros de 'Cannot read property of undefined'. O TypeScript te obriga a verificar null/undefined antes de acessar propriedades. Parece chato, mas cada verificação é um bug a menos em produção.
noImplicitAny — Nada de Any Escondido
// SEM noImplicitAny (o TypeScript aceita calado)
function processar(dados) {
// 'dados' é implicitamente 'any'
// Qualquer operação passa sem checagem
return dados.map(item => item.valor * 2);
}
// COM noImplicitAny (TypeScript exige tipo)
function processar(dados) {
// Erro: Parameter 'dados' implicitly has an 'any' type
}
// Jeito correto:
interface Item {
valor: number;
}
function processar(dados: Item[]): number[] {
return dados.map(item => item.valor * 2);
}
// Agora se alguém passa um array de strings, o compilador barra
// processar(['a', 'b']); // Erro de compilação
strictFunctionTypes — Compatibilidade de Funções
// strictFunctionTypes verifica compatibilidade de callbacks
interface Animal {
nome: string;
}
interface Cachorro extends Animal {
raca: string;
}
// SEM strictFunctionTypes (deixa passar)
type Handler = (animal: Animal) => void;
const handleCachorro: Handler = (cachorro: Cachorro) => {
console.log(cachorro.raca); // Perigoso! Nem todo Animal tem raca
};
// COM strictFunctionTypes (barra)
const handleCachorro: Handler = (cachorro: Cachorro) => {
// Erro: Type '(cachorro: Cachorro) => void' is not assignable
// to type 'Handler'
console.log(cachorro.raca);
};
// Jeito correto: use Animal e verifique
const handleAnimal: Handler = (animal: Animal) => {
if ('raca' in animal) {
console.log((animal as Cachorro).raca);
}
};
strictPropertyInitialization — Classes Seguras
// SEM strictPropertyInitialization
class UserService {
private db: Database; // Sem erro, mas db pode ser undefined
getUsers() {
return this.db.query('SELECT * FROM users');
// Runtime error se db não foi inicializado!
}
}
// COM strictPropertyInitialization
class UserService {
private db: Database;
// Erro: Property 'db' has no initializer and is not
// definitely assigned in the constructor
// Opção 1: Inicializar no constructor
constructor(db: Database) {
this.db = db;
}
// Opção 2: Valor padrão
private retries: number = 3;
// Opção 3: Definite assignment assertion (quando você tem certeza)
private config!: Config; // O ! diz "confie em mim"
}
useUnknownInCatchVariables — Catch Seguro
// SEM useUnknownInCatchVariables
try {
JSON.parse(texto);
} catch (error) {
// error é 'any' - aceita qualquer coisa
console.log(error.message); // Funciona, mas sem segurança
}
// COM useUnknownInCatchVariables
try {
JSON.parse(texto);
} catch (error) {
// error é 'unknown' - precisa verificar
// console.log(error.message); // Erro!
if (error instanceof Error) {
console.log(error.message); // Agora sim, seguro
} else {
console.log('Erro desconhecido:', String(error));
}
}
// Por que isso importa? Nem todo throw lança Error:
// throw "string de erro";
// throw 42;
// throw { custom: true };
// O catch precisa estar preparado pra qualquer coisa
Cada flag cobre uma brecha diferente. Juntas, elas formam uma rede de segurança que pega bugs em tempo de compilação — onde o custo de correção é próximo de zero.
Adoção Incremental em Projetos Existentes
Ligar strict: true num projeto grande de uma vez vai gerar centenas de erros. A estratégia certa é ativar uma flag por vez, corrigir e estabilizar antes de seguir.
// tsconfig.json - Adoção incremental
{
"compilerOptions": {
// Fase 1: Comece com essas
"strictNullChecks": true,
"noImplicitAny": true,
// Fase 2: Adicione depois
"strictFunctionTypes": true,
"strictBindCallApply": true,
// Fase 3: Finalize
"strictPropertyInitialization": true,
"noImplicitThis": true,
"useUnknownInCatchVariables": true,
"alwaysStrict": true
// Fase 4: Substitua tudo por
// "strict": true
}
}
// Dica: use @ts-expect-error pra erros que vai corrigir depois
function legacyFunction(data: any) {
// @ts-expect-error - TODO: tipar corretamente na sprint 15
return data.process();
}
O @ts-expect-error é melhor que @ts-ignore pra migração. Quando você corrige o erro, o @ts-expect-error avisa que não é mais necessário. O @ts-ignore fica lá pra sempre, escondendo problemas que talvez já não existam.
Benefícios Práticos do Strict Mode
Números concretos do impacto de ativar strict mode em projetos reais.
// Impacto documentado:
//
// Benefícios observados na prática (não são estatística auditada):
// - Menos crashes de null/undefined com strictNullChecks
// - Bugs de tipo aparecem no editor, não só em produção
// - Refatoração mais segura porque o compilador pega regressões
//
// Antes do strict mode:
function getConfig() {
return config; // Pode ser undefined, ninguém sabe
}
const port = getConfig().port; // Bomba em produção
// Depois do strict mode:
function getConfig(): Config | undefined {
return config;
}
const port = getConfig()?.port ?? 3000; // Seguro, com fallback
// O strict mode não te impede de nada.
// Ele te obriga a ser explícito sobre as decisões.
// "Esse valor pode ser null? Trate antes de usar."
// "Esse parâmetro aceita qualquer tipo? Defina qual."
Strict mode não é sobre restrição — é sobre clareza. O código fica mais explícito sobre o que pode dar errado. E quando as coisas são explícitas, ficam mais fáceis de manter, testar e refatorar.
Erros Comuns ao Usar Strict Mode
Tropeços frequentes com strict
Desativar strict porque 'dá muito erro': os erros já existem no código. Strict só torna eles visíveis. Desativar é como desligar o alarme de incêndio porque faz barulho.
Usar as any pra silenciar erros: type assertion pra any é pior que não ter strict. Você perde toda a segurança naquele ponto. Use narrowing (typeof, instanceof, in) pra resolver os erros de tipo corretamente.
Abusar do operador ! (non-null assertion): user!.name diz pro TypeScript 'confia, não é null'. Se for null, crash em runtime. Use ! só quando você tem certeza absoluta — e mesmo assim, prefira verificação explícita.
Não configurar strictPropertyInitialization com DI: frameworks de injeção de dependência inicializam propriedades fora do constructor. Use o ! (definite assignment) nesses casos: private service!: MyService.
Ativar tudo de uma vez em projeto legado: centenas de erros desmotivam o time. Vá flag por flag, sprint por sprint. Progresso constante é melhor que revolução frustrada.
Checklist do Strict Mode
TypeScript Seguro na Prática
Strict mode é o que separa projetos TypeScript amadores de profissionais. No CrazyStack, todo o código roda com strict: true desde o primeiro commit. Você aprende a lidar com null checks, tipagem de funções e classes seguras construindo um projeto real do zero.
Não tem atalho pra código seguro. Mas com strict mode ativado, o compilador trabalha junto com você.
Continue lendo
Como Configurar tsconfig no TypeScript
Domine cada opção do tsconfig.json e configure seu projeto com segurança.
Como Testar TypeScript com Jest
Configure Jest com TypeScript e escreva testes tipados com mocks e utilities.
Como Migrar JavaScript para TypeScript
Migre seu projeto JavaScript pra TypeScript sem quebrar tudo de uma vez.
Interface no TypeScript
Quando usar interface