This TypeScript error occurs when you enable the 'noUncheckedIndexedAccess' compiler option without also enabling 'strictNullChecks'. The 'noUncheckedIndexedAccess' option adds 'undefined' to indexed property types, which only makes sense when TypeScript is strictly tracking null and undefined values. The fix is to either enable 'strictNullChecks' or disable 'noUncheckedIndexedAccess'.
The error "'noUncheckedIndexedAccess' requires 'strictNullChecks'" appears when you try to use TypeScript's `noUncheckedIndexedAccess` compiler option without having `strictNullChecks` enabled. This is a dependency requirement because `noUncheckedIndexedAccess` fundamentally changes how TypeScript handles indexed property access. `noUncheckedIndexedAccess` is a strictness option that adds `undefined` to the type of properties accessed via index signatures when those properties aren't explicitly declared. For example, with this option enabled, accessing `obj["dynamicKey"]` on an object with an index signature returns `string | undefined` instead of just `string`. This behavior only makes sense when TypeScript is tracking null and undefined values strictly via `strictNullChecks`. Without `strictNullChecks`, TypeScript treats `null` and `undefined` as assignable to any type, so adding `undefined` to indexed access types would have no effect and could lead to confusion. The TypeScript compiler enforces this dependency to ensure consistent type safety. If you want the stricter checking of `noUncheckedIndexedAccess`, you must first enable `strictNullChecks` to properly handle the potential `undefined` values it introduces.
The simplest fix is to enable strictNullChecks in your tsconfig.json file. This is required for noUncheckedIndexedAccess to work properly:
{
"compilerOptions": {
"strictNullChecks": true,
"noUncheckedIndexedAccess": true
}
}If you're using the strict flag (which includes strictNullChecks), make sure it's enabled:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}After making this change, restart your TypeScript server in your IDE:
- VS Code: Press Cmd/Ctrl + Shift + P, then type "TypeScript: Restart TS Server"
- Other IDEs: Restart the IDE or rebuild the project
Test the fix by running:
npx tsc --noEmitIf you cannot enable strictNullChecks (e.g., legacy codebase compatibility), disable noUncheckedIndexedAccess:
{
"compilerOptions": {
"strictNullChecks": false,
"noUncheckedIndexedAccess": false
}
}Or remove the noUncheckedIndexedAccess option entirely (defaults to false):
{
"compilerOptions": {
"strictNullChecks": false
// noUncheckedIndexedAccess is not specified (defaults to false)
}
}Note: Disabling noUncheckedIndexedAccess means TypeScript won't add undefined to indexed property accesses, which could hide potential runtime errors. Consider whether your project can migrate to strictNullChecks: true instead.
If you're using strict: true, you cannot disable strictNullChecks individually. The strict flag bundles multiple strictness options including strictNullChecks.
TypeScript projects can have multiple tsconfig.json files (e.g., base config extended by others). Check all relevant files:
1. Look for extends:
{
"extends": "./tsconfig.base.json"
}2. Check the base file for strictNullChecks and noUncheckedIndexedAccess settings.
3. Look for tsconfig.json in parent directories - TypeScript searches up the directory tree.
4. **Check for tsconfig.*.json files** (e.g., tsconfig.build.json, tsconfig.test.json).
Example of resolving conflicts:
// tsconfig.base.json
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}
// tsconfig.json (extends base)
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
// No need to repeat - inherits from base
}
}If a child config overrides parent settings, ensure consistency:
// WRONG - child disables strictNullChecks while parent enables noUncheckedIndexedAccess
{
"extends": "./tsconfig.base.json",
"compilerOptions": {
"strictNullChecks": false // Conflict!
}
}The noUncheckedIndexedAccess option was introduced in TypeScript 4.1. Ensure you're using a compatible version:
# Check TypeScript version
npx tsc --version
# Update TypeScript if needed
npm install typescript@latest --save-dev
# or for a specific version
npm install [email protected] --save-devVersion requirements:
- TypeScript 4.1+: noUncheckedIndexedAccess option available
- TypeScript 4.0+: strictNullChecks fully stable
- Older versions: Consider upgrading for better type safety
If you're using an older TypeScript version that doesn't support noUncheckedIndexedAccess, you'll get a different error. Update your package.json:
{
"devDependencies": {
"typescript": "^5.0.0"
}
}After updating, delete node_modules and reinstall:
rm -rf node_modules
npm installSome build tools and frameworks have their own TypeScript configuration that might conflict:
Create React App (CRA):
CRA hides tsconfig.json. Eject or use [email protected]+ which includes TypeScript 4.x support.
Next.js:
Next.js has its own TypeScript configuration. Check next.config.js and ensure compatibility:
// next.config.js
module.exports = {
typescript: {
// Next.js ignores tsconfig.json errors by default in dev
ignoreBuildErrors: false, // Set to true only for temporary workarounds
}
}Angular:
Angular uses tsconfig.json but may have additional constraints in angular.json:
{
"projects": {
"my-app": {
"architect": {
"build": {
"options": {
"tsConfig": "tsconfig.app.json"
}
}
}
}
}
}Vite / Rollup / Webpack:
These tools use tsconfig.json directly. Ensure your build script references the correct config:
# Example build command
npx tsc -p tsconfig.build.jsonIf using a monorepo (TurboRepo, Nx, Lerna), check each package's tsconfig.json for consistency.
If you enable strictNullChecks, you may need to fix type errors in your code:
Common fixes for strictNullChecks errors:
1. Add null checks for potentially undefined values:
// Before: Error with strictNullChecks
const value = obj["key"]; // string | undefined
console.log(value.length); // Error: Object is possibly 'undefined'
// After: Add null check
const value = obj["key"];
if (value !== undefined) {
console.log(value.length); // OK
}2. Use optional chaining (?.):
const length = obj["key"]?.length; // number | undefined3. Provide default values:
const value = obj["key"] ?? "default"; // string4. Use type assertions when you're sure:
const value = obj["key"] as string; // Only if you're certain5. Update function signatures:
// Before
function getName(id: string): string {
return data[id]; // Might return undefined
}
// After
function getName(id: string): string | undefined {
return data[id]; // Explicit return type
}Run TypeScript in strict mode to find all issues:
npx tsc --strict --noEmitConsider incremental migration by enabling strictNullChecks in specific files first using // @ts-strict comments.
### Understanding noUncheckedIndexedAccess
The noUncheckedIndexedAccess compiler option changes how TypeScript handles indexed property access on objects with index signatures:
Without noUncheckedIndexedAccess (default):
interface EnvironmentVars {
NAME: string;
OS: string;
[propName: string]: string; // Index signature
}
declare const env: EnvironmentVars;
const nodeEnv = env.NODE_ENV; // Type: string (even though NODE_ENV isn't declared)With noUncheckedIndexedAccess: true:
const nodeEnv = env.NODE_ENV; // Type: string | undefinedThis option is particularly useful for:
- Configuration objects with dynamic keys
- Parsed JSON data
- Dictionary/map data structures
- Any object with an index signature
### Why strictNullChecks is Required
noUncheckedIndexedAccess adds undefined to indexed access types. Without strictNullChecks:
- undefined is assignable to any type
- The added undefined union would have no effect
- TypeScript would incorrectly assume values are never undefined
- The option would provide false sense of safety
### Migration Strategy for Large Codebases
If you have a large codebase without strictNullChecks:
1. Enable per file: Use // @ts-strict comments in individual files
2. Use skipLibCheck: Temporarily set skipLibCheck: true to ignore library type errors
3. Gradual rollout: Enable for new code first, migrate old code incrementally
4. TypeScript 5.0+: Use exactOptionalPropertyTypes for even stricter checking
### Performance Considerations
Enabling strictNullChecks and noUncheckedIndexedAccess:
- Slightly increases compilation time (more type checking)
- Improves runtime safety (catches potential errors)
- May require more explicit code (null checks, optional chaining)
For very large projects, measure compilation time impact and consider incremental builds.
### Framework-Specific Notes
React: With noUncheckedIndexedAccess, accessing dynamic object properties in state may require null checks:
const [data, setData] = useState<Record<string, string>>({});
const value = data["key"]; // string | undefinedNode.js: File system operations often return undefined for missing keys:
const env = process.env;
const apiKey = env["API_KEY"]; // string | undefined (with noUncheckedIndexedAccess)Testing: Update test assertions to handle undefined cases:
expect(obj["key"]).toBeDefined(); // Instead of just checking value### Alternative: Use Record Types
Instead of index signatures, consider using Record types with known keys:
// Instead of index signature
interface Config {
[key: string]: string;
}
// Use Record with specific keys
type Config = Record<"apiUrl" | "timeout" | "retries", string>;This provides better type safety without needing noUncheckedIndexedAccess.
Function expression requires a return type
Function expression requires a return type
Value of type 'string | undefined' is not iterable
How to fix "Value is not iterable" in TypeScript
Type 'undefined' is not assignable to type 'string'
How to fix "Type undefined is not assignable to type string" in TypeScript
Type narrowing from typeof check produces 'never'
How to fix "Type narrowing produces never" in TypeScript
Type parameter 'T' has conflicting constraints
How to fix "Type parameter has conflicting constraints" in TypeScript