Skip to Content
tsconfig strict: Turn It On Without 200 Errors
Beginner
0 likes
Tutorials

tsconfig strict: Turn It On Without 200 Errors

Count what each strict flag costs, turn them on one at a time, park one stubborn error with ts-expect-error, and finish with strict true. After this, an old project can move to strict in steps.

Turning on "strict": true in an old project can print 200 errors in one go. You do not have to fix them in one go. This page shows how to turn strict mode on in steps, count what each step costs, and finish with strict on and nothing switched off.

What strict is made of

strict is a bundle of separate checks. The two that produce most of the errors in a JavaScript-to-TypeScript migration are:

  • noImplicitAny: parameters and variables that would silently be any.
  • strictNullChecks: places where null or undefined can reach code that expects a value.

A third one, useUnknownInCatchVariables, makes the e in catch (e) an unknown, so e.message needs a check first.

The sample file

This old code is typical. It compiles with strict mode off.

{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "strict": false,
    "noEmit": true
  },
  "include": ["src"]
}
function discount(price, rate) {
  return price - price * rate;
}

let customer: string = null;

function firstLong(items: string[]) {
  return items.find((item) => item.length > 3);
}

console.log(firstLong(["ab", "abcd"]).toUpperCase());

try {
  JSON.parse("{");
} catch (e) {
  console.log(e.message);
}

export { discount, customer };
npx tsc

No output means no errors. That is your baseline.

Step 1: count what each flag would cost

Turn on one flag at a time from the command line, without editing the config. The count tells you where to start. The grep -c counting works on macOS and Linux. On Windows, drop the | grep part and count the lines by eye.

npx tsc --noImplicitAny | grep -c "error TS"
npx tsc --strictNullChecks | grep -c "error TS"
npx tsc --useUnknownInCatchVariables | grep -c "error TS"
npx tsc --strict | grep -c "error TS"
2
2
1
5

Four numbers. Two come from noImplicitAny, two from strictNullChecks, one from the catch, and strict shows the total. On a real project the numbers are bigger, but the idea is the same: you can see which flag is the expensive one before you commit to it.

Step 2: switch on the cheap ones first

Edit tsconfig.json. Start with the mechanical flag and leave the hard one off for now.

{
  "compilerOptions": {
    "target": "es2022",
    "module": "nodenext",
    "strict": true,
    "strictNullChecks": false,
    "noEmit": true
  },
  "include": ["src"]
}
npx tsc
src/legacy.ts(1,19): error TS7006: Parameter 'price' implicitly has an 'any' type.
src/legacy.ts(1,26): error TS7006: Parameter 'rate' implicitly has an 'any' type.
src/legacy.ts(16,17): error TS2339: Property 'message' does not exist on type 'unknown'.

"strict": true turns everything on, and then "strictNullChecks": false turns that one flag back off. That pattern is the useful part. You get the bundle's other checks now, and the hard flag is one line to remove later. Fix the errors that show up, then run tsc again. For this file, that means two number types and a check in the catch.

function discount(price: number, rate: number): number {
  return price - price * rate;
}

try {
  JSON.parse("{");
} catch (e) {
  console.log(e instanceof Error ? e.message : e);
}

export { discount };

Step 3: park a stubborn error on purpose

If one line needs more time than you have, mark it so it cannot be forgotten.

// TODO: remove when the customer lookup is typed.
// @ts-expect-error
let customer: string = null;

export { customer };

The comment silences the error on the next line only. The useful part is what happens once you fix the line.

// @ts-expect-error
let customer: string = "Ana";

export { customer };
src/fixed.ts(1,1): error TS2578: Unused '@ts-expect-error' directive.

When the error is gone, the directive itself becomes an error, so the comment cannot hide in your code after the problem is solved. // @ts-ignore does not do that, which is why this one is the better choice.

Step 4: finish

Remove "strictNullChecks": false from the config, fix what appears, and you are on full strict with a clean compile. The final config has "strict": true and nothing after it.

For a very large project

If fixing a whole project is too much at once, keep the old config and add a second one that is strict and covers only the folders you have already cleaned.

{
  "extends": "./tsconfig.json",
  "compilerOptions": { "strict": true, "strictNullChecks": true },
  "include": ["src/clean"]
}

The second flag matters here. Your main config still has "strictNullChecks": false from step 2, and a setting written in the main file stays in force unless the new file overrides it. Run npx tsc -p tsconfig.strict.json on the build server next to the normal compile. As each folder is fixed, add it to include. When the list is everything, delete the second file and set strict in the main one.

⚠ Warning: Do not leave the migration at "strict: false with a TODO". Without a date or a ticket, it will not happen.

Related course: TypeScript for Beginners.

About

Count what each strict flag costs, turn them on one at a time, park one stubborn error with ts-expect-error, and finish with strict true. After this, an old project can move to strict in steps.

Responsible
Mary Q
Last Update
10/19/2026
Reading Time
5 min
Was this helpful?
​ 0 ​ 0

Comments (0)

Sign in to comment

No comments yet.