An index signature ({ [name: string]: string }, or Record<string, string>) allows any property name, so env.HOEM is as valid as env.HOME. noPropertyAccessFromIndexSignature makes the difference visible: properties the type declares by name are read with a dot, and the others must use brackets.
The rule changes nothing at run time. Its point is that bracket access marks a name the checker cannot verify, so a typo in a dotted name is never hidden behind an index signature.
At a glance
| Code | TS4111 |
|---|---|
| Message | Property '{0}' comes from an index signature, so it must be accessed with ['{0}']. |
| TypeScript's category | error |
| Listed under | Unknown names and members |
| Turned on by | noPropertyAccessFromIndexSignature |
| In .js files | Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file |
The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} is filled in by tsc for each error.
What it looks like
/** @type {{ mode: string, [name: string]: string }} */
const env = { mode: "production", HOME: "/home/ada" };
console.log(env.mode);
console.log(env.HOME);error TS4111: Property 'HOME' comes from an index signature, so it must be accessed with ['HOME'].jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": [],
"noPropertyAccessFromIndexSignature": true
},
"include": ["**/*.js"]
} What causes it
- Reading an environment variable, a header or a dictionary entry with a dot (
env.HOME) from a type that only has an index signature for it.
How to fix it
Use bracket access
Write env["HOME"]. Names the type declares, such as mode in the example, keep their dot.
/** @type {{ mode: string, [name: string]: string }} */
const env = { mode: "production", HOME: "/home/ada" };
console.log(env.mode);
console.log(env["HOME"]);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": [],
"noPropertyAccessFromIndexSignature": true
},
"include": ["**/*.js"]
} Or declare the property
If the name is always there, add it to the type ({ HOME: string, [name: string]: string }); then the dot is fine and a typo in it is an error.
Gotchas
process.envis typed with an index signature in@types/node, soprocess.env.PORTis TS4111 under this option; the environment variables recipe covers it.
Sources
- TSConfig Reference: noPropertyAccessFromIndexSignature · TypeScript
- diagnosticMessages.json (TypeScript 5.9.3) · TypeScript on GitHub
Last reviewed 21 October 2026.