Uma lista vazia não parece perigosa até o código executar users[0].name. Um dicionário também parece completo até uma chave vir de uma requisição, de um arquivo ou de uma configuração que mudou. Sem uma checagem, o TypeScript pode tratar os dois acessos como se o valor existisse.
noUncheckedIndexedAccess muda esse contrato. Ao ativar a opção, uma leitura por índice que pode não encontrar um valor passa a incluir undefined. O compilador não escolhe a correção por você. Ele obriga o código a decidir entre uma guarda, um fallback, outra forma de iteração, um Map ou uma invariável que você consegue provar.
Este artigo mostra o comportamento em arrays e objetos com chaves dinâmicas, uma fixture mínima verificada com TypeScript 5.9.3 e uma migração em etapas. A opção trata de segurança estática do código. Ela não valida o JSON que chega pela rede.

Resposta curta
- Ative
noUncheckedIndexedAccessjunto destrictquando quiser que leituras indexadas expressem a possibilidade de ausência.- Trate
array[i]erecord[key]como valores que podem serundefined.- Prefira
for...of, uma guarda explícita ou um fallback que faça sentido para o domínio.- Use
!somente quando uma invariável foi estabelecida fora daquela linha e continua verificável.
O que noUncheckedIndexedAccess muda?
Segundo a documentação do TypeScript sobre noUncheckedIndexedAccess, a opção adiciona undefined a uma propriedade não declarada coberta por uma index signature. Em um array, a mesma ideia vale para uma posição que pode estar fora dos limites. O tipo passa a representar a ausência que já era possível em runtime.
Sem a opção, este código compila mesmo que users esteja vazio:
interface User {
id: string;
name: string;
}
const users: User[] = [];
const first = users[0];
console.log(first.name);
Com noUncheckedIndexedAccess: true, first é User | undefined. A linha que acessa name precisa escolher o que fazer quando não existe primeiro usuário:
const first = users[0];
if (first) {
console.log(first.name);
} else {
console.log("nenhum usuário encontrado");
}
O ganho não é fazer o array ficar mais seguro em runtime. O array continua podendo estar vazio. O ganho é tirar uma suposição escondida do tipo e colocar a decisão no ponto em que o programa realmente sabe se a ausência é esperada, um erro ou um caso para tentar novamente.
Por que strict não ativa essa opção?
O TypeScript 4.1 explica que noUncheckedIndexedAccess pode gerar ruído em muitos arquivos e, por isso, ela não faz parte do grupo ativado por strict. Um projeto pode usar strict: true e ainda tratar items[index] como se sempre retornasse um item.
Esse detalhe muda a leitura do tsconfig.json. strict é um bom ponto de partida, mas não é uma promessa de que todo acesso por índice foi verificado. Para habilitar a checagem, declare a opção de forma explícita:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}
A opção não transforma todos os tipos em T | undefined. Propriedades declaradas continuam conhecidas. O efeito aparece onde a chave ou a posição não é garantida pelo tipo, como um índice numérico de array ou uma chave string usada contra um Record<string, T>.
Onde os erros aparecem primeiro?
O FAQ do TypeScript chama essa configuração de uma verificação ampla: ela não tenta provar que cada acesso está dentro dos limites. Por isso, a primeira compilação costuma apontar padrões que pareciam inofensivos, mas dependiam de dados presentes.
| Leitura | Tipo com a opção | Correção que costuma comunicar melhor a intenção |
|---|---|---|
users[0] |
User | undefined |
testar a ausência ou usar uma API que já retorne uma opção explícita |
users[index] |
User | undefined |
guardar o item em uma variável e estreitar essa variável |
usersById[id] |
User | undefined |
tratar chave desconhecida ou usar Map.get com a mesma honestidade |
path.split("/")[3] |
string | undefined |
validar a estrutura antes de usar a parte |
map.get(id) |
já pode ser User | undefined |
manter o tratamento de ausência |
Uma armadilha comum é esperar que um teste de limite resolva tudo:
for (let index = 0; index < users.length; index += 1) {
users[index].name;
}
O release note do TypeScript registra que até um loop com index < length pode continuar produzindo um erro. O compilador não transforma esse teste em uma prova permanente sobre uma estrutura que pode sofrer mutação. Se o índice é realmente necessário, leia o item, teste o resultado e só depois acesse suas propriedades.
Como corrigir sem usar ! para calar o compilador?
Escolha a correção pelo significado da ausência. Quando todo item presente deve ser processado, for...of elimina o índice e expressa essa intenção diretamente:
for (const user of users) {
console.log(user.name);
}
Quando a ausência é possível e muda o resultado, use uma guarda:
const user = usersById[userId];
if (!user) {
return { ok: false, reason: "user-not-found" };
}
return { ok: true, user };
Um fallback também pode ser correto, mas precisa pertencer ao domínio. const limit = settings[key] ?? defaultLimit comunica uma regra. Já settings[key]! apenas afirma que a regra existe sem registrá-la no código. Se alguém renomear a chave, mover a inicialização ou mudar a origem dos dados, o cast não encontra o problema.
Para dicionários com muitas leituras e chaves externas, avalie se Map representa melhor a operação. Map.get já retorna T | undefined, então a decisão de ausência aparece mesmo sem essa opção. Isso não significa que Map seja sempre superior. Significa que o tipo acompanha melhor um conjunto em que a chave pode não existir.
Uma boa migração não transforma todos os erros em if (!value) return. Ela classifica cada leitura: ausência normal, configuração inválida, dado que precisa de fallback ou invariável garantida por outra etapa. O tipo só fica honesto quando o comportamento escolhido também é.
Como ativar a opção sem parar o projeto inteiro?
Trate a ativação como uma mudança de contrato do compilador. Antes de corrigir qualquer linha, rode o typecheck atual e registre qual comando o CI usa. Depois faça a mudança em uma configuração ou pacote que tenha uma fronteira clara.
Uma sequência pequena ajuda:
- Ative
noUncheckedIndexedAccessnotsconfigdo pacote escolhido. - Rode
npx tsc --noEmitcom o mesmo projeto usado pelo CI. - Separe os erros entre arrays, records, strings divididas e tipos de bibliotecas.
- Corrija cada grupo com guarda, iteração, fallback ou uma estrutura de dados adequada.
- Execute os testes que cobrem listas vazias, chaves desconhecidas e configurações incompletas.
- Mantenha a opção ligada no CI para que novos acessos não reintroduzam a suposição.
Nesta página, eu verifiquei uma fixture mínima com strict, noUncheckedIndexedAccess e noEmit usando TypeScript 5.9.3. Ela compila depois de estreitar o item lido e demonstra o comportamento descrito pela documentação. Isso não é um benchmark de migração: uma base real pode ter erros em tipos de dependências, geradores, testes e código que mistura JavaScript com TypeScript.
Se o pacote faz parte de um monorepo, a opção pode ser introduzida por uma fronteira de projeto e depois avançar para os dependentes. O artigo sobre Project References no TypeScript explica como separar projetos e manter a ordem do build explícita. A preocupação aqui é diferente: o build graph organiza a compilação, enquanto esta opção muda o tipo dos acessos dentro dela.
Se a leitura faz parte do retorno de uma requisição, tipar sucesso e erro de um fetch em TypeScript ajuda a separar a falha de transporte da ausência dentro do dado.
O que a opção não verifica?
noUncheckedIndexedAccess age durante a checagem do código que você escreveu. Ela não inspeciona um JSON vindo da rede, não confirma que uma chave externa tem o formato esperado e não impede que outra camada passe um valor errado por meio de any. Uma interface TypeScript também não faz essa validação em runtime.
Quando o valor atravessa uma fronteira externa, leia-o como unknown e valide sua forma antes de usar. A validação de JSON externo em TypeScript cobre essa etapa. Usar as duas proteções faz sentido: a validação prova o valor recebido, enquanto noUncheckedIndexedAccess mantém honestas as leituras que o programa faz depois.
A opção também não detecta todos os problemas de objetos dinâmicos. Uma chave como __proto__, uma colisão de propriedade herdada ou um contrato de autorização exige uma decisão de runtime. Para esses casos, combine tipos com validação, estruturas de dados e testes que alcancem a fronteira real.
Use testes unitários ou de integração em Node.js para decidir se a correção precisa provar apenas a lógica de estreitamento ou também a fonte que produz as chaves e posições.
Perguntas frequentes
noUncheckedIndexedAccess faz parte de strict?
Não. O release note do TypeScript 4.1 explica que a opção não é ativada por strict porque pode gerar muitos erros de migração. Declare "noUncheckedIndexedAccess": true separadamente quando quiser que arrays e index signatures expressem a possibilidade de undefined.
Por que for...of costuma resolver o erro do array?
for...of entrega cada elemento existente da iteração, em vez de pedir ao compilador que prove o resultado de um índice numérico. Ele não torna uma fonte externa confiável nem impede mutações fora do loop. Apenas escolhe uma operação cujo contrato já representa melhor o processamento de todos os itens presentes.
Posso usar ! depois de ativar a opção?
Pode, mas o operador deve representar uma invariável que o programa realmente estabeleceu. Se uma função só pode ser chamada depois de carregar uma configuração obrigatória, documente e teste essa pré-condição. Para uma chave, posição ou resposta que pode faltar normalmente, ! remove a evidência sem corrigir o comportamento.
A opção substitui validação de JSON?
Não. Ela verifica tipos e acessos no código compilado. JSON, variáveis de ambiente e respostas HTTP chegam em runtime e precisam de uma validação própria. Trate a entrada como unknown, valide o formato e só depois use o código TypeScript que continua protegido contra índices ausentes dentro do fluxo.
Conclusão
Ativar noUncheckedIndexedAccess torna explícita uma pergunta que muitos arrays e records escondem: o valor está realmente lá? A resposta pode ser uma guarda, um fallback, for...of, Map.get ou uma invariável verificável. O compilador não impõe uma política única, mas deixa de aceitar o silêncio como prova.
Comece por um pacote pequeno, rode o mesmo typecheck do CI e corrija os erros pelo significado da ausência. Não use o operador ! para transformar uma dúvida de dados em certeza de tipo. E mantenha a fronteira clara: esta opção melhora o código que você compila, enquanto valores externos continuam precisando de validação em runtime.
Fontes consultadas
- TypeScript, "TSConfig: noUncheckedIndexedAccess", consultado em 2026-10-05.
- TypeScript, "TypeScript 4.1 release notes", consultado em 2026-10-05.
- TypeScript Wiki, "FAQ: Assume Array Access Might Be Out of Bounds", consultado em 2026-10-05.
- DEV Community, "TypeScript's noUncheckedIndexedAccess: Turn It On, See What Breaks", consultado em 2026-10-05. Usado como sinal de linguagem e migração, não como prova do comportamento do compilador.
Este texto foi produzido com assistência de IA para organizar pesquisa, rascunhar prosa, localizar versões e criar a ilustração. A fixture e as afirmações técnicas foram verificadas contra a documentação citada; a imagem é explicativa e não representa uma saída real do compilador.