Learn why TypeScript throws TS1100 when eval or arguments is used as a name in a strict-mode script file, and how alwaysStrict and a rename fix it.
TS1100 means you used eval or arguments as a name — for a variable, a parameter, a function, a destructured binding or the left-hand side of an assignment — in a file that is running under ECMAScript strict mode. Strict mode reserves those two identifiers so that engines can reason about scopes without worrying that eval has been replaced or that arguments no longer refers to the call's argument list.
The check lives in TypeScript's binder, not in the type checker, which is why it fires before anything is type-checked and why no amount of annotation makes it go away. What decides whether it fires at all is the strictness of the file: a plain script file with a "use strict" directive at the top, or any script file when alwaysStrict is on. Because strict: true turns alwaysStrict on, this error has a habit of appearing in old script-style helpers the day a project enables strict — code that compiled for years suddenly stops.
// The general shape of the error:
var arguments = ["--watch", "--verbose"]
// ~~~~~~~~~ Error: Invalid use of 'arguments' in strict mode.Context decides which code you get. The same mistake inside a module (any file with an import or export) is reported as TS1215, and inside a class body as TS1210, because modules and class bodies are strict by definition and the compiler can phrase the explanation more precisely there. Only the free-standing script case produces TS1100.
arguments in a Script File After Enabling strictThis is the classic. The file has no import and no export, so it is a script, not a module — and it was written back when sloppy mode let arguments be an ordinary name. Switching the project to strict: true enables alwaysStrict, every file becomes strict, and the binder starts complaining.
// ❌ Broken — cli-flags.ts, no imports/exports, tsconfig has "strict": true
var arguments = ["--watch", "--verbose"]
// ~~~~~~~~~ Error: Invalid use of 'arguments' in strict mode.
function hasWatchFlag() {
return cliHasFlag("--watch")
}// ✅ Fixed — a name that is not reserved, and a const while we are here
const cliArguments = ["--watch", "--verbose"]
function hasWatchFlag() {
return cliArguments.indexOf("--watch") !== -1
}The rename is the whole fix. Resist the temptation to set "alwaysStrict": false to make the build go green: that flag does not just silence the diagnostic, it changes the JavaScript TypeScript emits. Sloppy-mode output treats assignments to undeclared variables as globals, has different this binding in plain function calls, and silently ignores writes to read-only properties — a much larger behavioural change than renaming one variable.
evaleval reads like a perfectly good name for "the expression to evaluate", which is exactly why it shows up in rule engines, template renderers and small expression parsers. Strict mode forbids it in any binding position, parameters included.
// ❌ Broken
"use strict"
function evaluateRule(eval: string) {
// ~~~~ Error: Invalid use of 'eval' in strict mode.
return eval.trim().length > 0
}// ✅ Fixed — say what the parameter actually holds
"use strict"
function evaluateRule(expression: string) {
return expression.trim().length > 0
}The same applies to the function's own name: function eval(expression: string) {} is rejected for the same reason. Pick a name that describes the value — expression, source, formula, predicate — and the error disappears along with the ambiguity about whether you meant the global eval.
argumentsDestructuring introduces bindings too, and the binder checks them exactly like a var. This one is easy to walk into by accident, because the name comes from the data: job definitions, CLI manifests and CI configs all like to call their parameter list arguments.
// ❌ Broken
"use strict"
const jobPayload = { command: "build", arguments: ["--watch"] }
const { command, arguments } = jobPayload
// ~~~~~~~~~ Error: Invalid use of 'arguments' in strict mode.// ✅ Fixed — rename the binding, keep the property name
"use strict"
const jobPayload = { command: "build", arguments: ["--watch"] }
const { command, arguments: jobArguments } = jobPayload
console.log(command, jobArguments)Note what did not have to change: the object still has a property called arguments. Property names are not bindings, so jobPayload.arguments is completely legal in strict mode. Only the local name you introduce is restricted, and arguments: jobArguments renames exactly that.
argumentsWhen a function is migrated from old JavaScript, its parameters usually come along unchanged. A parameter called arguments was legal in the original sloppy-mode file and is not legal once the file is strict — and because the parameter is contextually typed here, the only thing the compiler says is TS1100.
// ❌ Broken
"use strict"
type JobRunner = (command: string, args: string[]) => string
const runJob: JobRunner = function (command, arguments) {
// ~~~~~~~~~ Error: Invalid use of 'arguments' in strict mode.
return command + " " + arguments.join(" ")
}// ✅ Fixed
"use strict"
type JobRunner = (command: string, args: string[]) => string
const runJob: JobRunner = function (command, jobArguments) {
return command + " " + jobArguments.join(" ")
}There is a second reason to rename beyond the diagnostic: inside a function expression, arguments already means something — the implicit arguments object of that call. Shadowing it with a parameter makes the body ambiguous to every reader, and converting the function to an arrow function later would quietly change what the name refers to.
Rename the binding. This is the fix in essentially every case, and it is a local, mechanical change: arguments → cliArguments / jobArguments / values, eval → expression / source. The names are reserved for the built-ins by the language, so there is no version of the code where keeping them is correct.
Read the column in the error, not just the line. The binder points at the exact binding position, which tells you which of the four cases you have — a declaration, a parameter, a destructured element or an assignment target. A const { arguments } = payload and a var arguments are the same error with very different fixes (arguments: jobArguments versus a plain rename).
Do not switch alwaysStrict off. It will make the message disappear and it will change your emitted JavaScript to sloppy mode, where accidental globals, different this binding and silent failed writes all come back. alwaysStrict is part of strict, so disabling it is a project-wide regression traded for one rename.
Do not reach for // @ts-ignore either. It will silence TS1100 and your build will go green — but it changes nothing about what gets emitted. The output still opens with "use strict", so that same line throws SyntaxError: Unexpected eval or arguments in strict mode the moment the file is loaded. That is the worse failure mode: you have traded a compile error, fixable by a rename, for a crash in production.
Decide whether the file should be a module. If a script-style file is really part of your application rather than a global-scope helper, adding export {} (or real imports and exports) makes it a module. That changes the diagnostic from TS1100 to TS1215 — it does not fix anything on its own, but a module is the right shape for application code, and the rename is needed in both worlds.
Keep it from coming back. Turn on the ESLint rule no-shadow-restricted-names, which catches eval and arguments as binding names in the editor, long before tsc runs. Pairing that with strict: true left on permanently means the next legacy file you add gets flagged while you are still writing it.
TS1100 fires when eval or arguments is used as a binding name inside a file that is in strict mode. "Binding name" covers more ground than people expect: variable declarations, function names, parameters, destructured elements and assignment targets all count.
The strictness comes from one of two places — a literal "use strict" directive at the top of the file, or the alwaysStrict compiler option, which strict: true enables. Without either of those, the very same script file compiles without complaint, which is why the error so often appears on untouched code right after a tsconfig change.
Nothing about the variable changed; the rules that apply to it did. strict: true implies alwaysStrict: true, which puts every file into ECMAScript strict mode and emits a "use strict" directive into the output. Strict mode reserves eval and arguments, so a name that was fine in sloppy mode is now a syntax-level error.
// Compiles clean without alwaysStrict, reports TS1100 with it:
var arguments = ["--watch"]Rename the variable rather than turning the flag back off. alwaysStrict is not cosmetic — switching it off makes TypeScript emit sloppy-mode JavaScript, which has genuinely different runtime semantics for this, for undeclared assignments and for writes to frozen objects.
They are the same check reported from three different contexts. TS1100 is the script case: a file with no import or export that is strict because of a directive or alwaysStrict. TS1215 — "Invalid use of 'arguments'. Modules are automatically in strict mode." — is the same mistake in a module, where strict mode is not optional. TS1210 is the class-body case, where the message spells out that code inside a class is always evaluated in strict mode.
export {} // makes this a module
var arguments = ["--watch"] // now TS1215 instead of TS1100Which code you see tells you something about the file, but nothing about the fix: in all three cases you rename the binding. The nearby TS1212 and TS1214 cover the other strict-mode identifier restrictions, such as using a reserved word like implements or package as a name.
Browse all TypeScript practice challenges to keep sharpening your type-level skills.
Track your progress through 200+ hands-on challenges. Free, sign in with GitHub.
Or start solving right away: explore all TypeScript challenges