strict is a shorthand. It turns on a family of checks that can each be set on their own: in TypeScript 5.9 that is noImplicitAny, strictNullChecks, strictFunctionTypes, strictBindCallApply, strictPropertyInitialization, strictBuiltinIteratorReturn, noImplicitThis, useUnknownInCatchVariables and alwaysStrict.
In a JavaScript project the two that change the most are noImplicitAny, which makes every untyped parameter an error (TS7006), and strictNullChecks, which makes you handle null and undefined. TypeScript 6.0 makes strict the default, so write it either way to keep a config meaning the same thing across versions.
At a glance
| Write | "strict": true for new code; on an existing codebase, start without it and turn it on once the first errors are fixed |
|---|---|
| On the command line | --strict |
| Type | boolean |
| Default in TypeScript 5.9 | false |
| Default from TypeScript 6.0 | true (TypeScript 6.0) |
| TypeScript's description | Enable all strict type-checking options. |
| In the quick-start setups |
|
| Generator, relaxed | false |
| Generator, recommended | true |
| Generator, strict | true |
The description is quoted from TypeScript's own option list (Apache-2.0); see the notices. The setup values are the checked configs on the quick-start pages. The generator rows are what the jsconfig generator writes at each level.
Examples
/**
* @param {{ id: number, name: string }[]} users
* @param {number} id
*/
export function findUser(users, id) {
return users.find((u) => u.id === id);
}
export function greet(name) {error TS7006: Parameter 'name' implicitly has an 'any' type.
return `Hello, ${name}`;
}
const users = [{ id: 1, name: "Ada" }];
const user = findUser(users, 2);
console.log(user.name);error TS18048: 'user' is possibly 'undefined'.jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": [
"*.js"
]
} /**
* @param {{ id: number, name: string }[]} users
* @param {number} id
*/
export function findUser(users, id) {
return users.find((u) => u.id === id);
}
export function greet(name) {
return `Hello, ${name}`;
}
const users = [{ id: 1, name: "Ada" }];
const user = findUser(users, 2);
console.log(user.name);jsconfig.json for this example
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": false,
"target": "es2022",
"module": "nodenext",
"types": []
},
"include": [
"*.js"
]
} What strict turns on
Each member except strictBuiltinIteratorReturn has its own page with the same code checked both ways:
noImplicitAny: parameters and values that could only beanystrictNullChecks:nullandundefinedas their own typesstrictFunctionTypes: parameter types checked when one function type is assigned to anotherstrictBindCallApply: arguments passed throughbind,callandapplystrictPropertyInitialization: class fields that are typed but never setnoImplicitThis:thiswith no known typeuseUnknownInCatchVariables:catch (err)asunknownalwaysStrict: every file parsed in strict modestrictBuiltinIteratorReturn(TypeScript 5.6): the value a finished built-in iterator returns isundefined, notany
Turning one check back off
An option you set yourself wins over strict. "strict": true with "strictPropertyInitialization": false keeps every strict check except that one. That is a reasonable middle step for a codebase with many classes, and the order you list them in does not matter.
{
"compilerOptions": {
"checkJs": true,
"noEmit": true,
"strict": true,
// every strict check except this one
"strictPropertyInitialization": false
}
} The family grows
New TypeScript releases add checks to strict: useUnknownInCatchVariables joined in 4.4 and strictBuiltinIteratorReturn in 5.6. Upgrading TypeScript can therefore report errors in code that passed before, without any change to your config. Read the release notes of each minor version before you move to it.
Stricter options that strict leaves off
These are not part of strict and are worth considering once it passes: noUncheckedIndexedAccess, exactOptionalPropertyTypes, noImplicitReturns, noFallthroughCasesInSwitch, noImplicitOverride, noUnusedLocals and noUnusedParameters, noPropertyAccessFromIndexSignature and noUncheckedSideEffectImports. The strict level of the jsconfig generator adds the first four.
Gotchas
- Without
strict, a.jsfile is checked loosely: untyped parameters areanywithout complaint andnullfits any type. Code can passnpm run lintand still fail on the firstundefined. - A config with no
strictline meansfalsein TypeScript 5.9 andtruein 6.0. Write the line.
Questions
Should I turn on strict in an existing JavaScript project?
Eventually. Start with checkJs alone, fix what it finds, then turn on strict (or noImplicitAny first, since it reports the most). The checkJs page describes the order.
Is strict on by default?
Not in TypeScript 5.9, where it defaults to false. TypeScript 6.0 changes the default to true.
Sources
- TSConfig Reference: strict · TypeScript
- TypeScript 2.3 release notes · TypeScript handbook
- TypeScript 4.4 release notes · TypeScript handbook
- TypeScript 5.6 release notes · TypeScript handbook
- TypeScript 6.0 release notes · TypeScript handbook
Last reviewed 20 October 2026.