strict mode in TypeScript is eight checks pretending to be one boolean. Knowing which check fired on a given error is the difference between fixing the bug and disabling the messenger.
What strict: true actually flips on
The Vite scaffold gives you strict: true in tsconfig.app.json. That single flag turns on a bundle. As of TypeScript 6.0, the bundle is:
noImplicitAny— Every parameter and variable needs an explicit or inferable type. No silentany.strictNullChecks—nullandundefinedare no longer assignable to every type. You have to widen explicitly (string | null).strictFunctionTypes— Function parameters are checked contravariantly. Prevents some sneaky subclass-substitution bugs.strictBindCallApply—.bind(),.call(),.apply()argument types are checked.strictPropertyInitialization— Class fields must be assigned in the constructor (or marked with!).noImplicitThis—thiswith implicitanyis an error.alwaysStrict— Emits"use strict"at the top of every file (also affects parsing).useUnknownInCatchVariables—catch (e)gives youunknowninstead ofany— you have to narrow.
You don't have to memorize all eight. You just need to read TS error messages with the awareness that the message names which check fired.
strict: true in your scaffold? That's expected. This lesson shows it explicitly, the way the TypeScript 5.x Vite template did. TypeScript 6.0 made strict the default, so the current Vite template dropped the now-redundant line — a fresh tsconfig.app.json may have no strict key at all. Strict mode is still fully on, and every check above applies identically. (If you're upgrading an older project, keep your explicit strict: true — nothing changes.)React-specific TS settings
Beyond strict, three settings matter for React:
"jsx": "react-jsx"— The modern JSX transform. You no longer needimport React from 'react'in every file just to use JSX."moduleResolution": "bundler"— TypeScript resolves imports the way Vite/esbuild/Rollup do (no.jsextension required)."target": "ES2022"or newer — Lets you use top-level await, private class fields, and other modern JS without down-leveling.
The Vite scaffold's split: app + node configs
You'll see three tsconfig files: tsconfig.json (the root reference manifest), tsconfig.app.json (for your src/ code), tsconfig.node.json (for Vite's config files themselves, which run in Node). The split exists because Node's vite.config.ts and your browser-bound React code have different DOM lib requirements. Don't merge them.
Reading a strict-mode error
When you see Argument of type 'string | undefined' is not assignable to parameter of type 'string'. — that's strictNullChecks talking. Fix: narrow with a guard (if (value === undefined) return;), provide a default (value ?? ""), or widen the parameter type to accept undefined. Don't suppress with ! (the non-null assertion) unless you've actually verified the value can't be undefined at this point.
! trap. Postfix ! is TypeScript's 'trust me, this isn't null' operator. It silences the type checker but the runtime can still blow up. Every ! in your code is a debt you've taken. Pay it down by adding a real guard.
For anyone wondering why strict is missing from tsconfig.app.json, this is expected with TypeScript 6.0+. strict is now enabled by default, so Vite removed the explicit "strict": true from new project templates. If you were looking for it and couldn't find it, these references explain the change:
TypeScript 6.0 announcement: https://devblogs.microsoft.com/typescript/announcing-typescript-6-0/#simple-default-changes
Vite PR: https://github.com/vitejs/vite/pull/22110