TLDR
Strict mode in TypeScript turns on 8 safety checks at once with one line: "strict": true in your tsconfig.json. It catches null errors, missing types, uninitialized class properties, and more before your code ever runs. Always enable it on new projects. On older projects, turn on the 8 flags one at a time and fix errors as you go.
What is Strict Mode in TypeScript?
By default, TypeScript is pretty relaxed. It lets you skip types in some places. It does not check for null on every value. It allows some patterns that can crash at runtime.
Strict mode fixes all of that. It is a single switch that turns on a group of type-checking rules all at once.
Think of it like turning on every warning light in a car instead of just the engine light. You see more problems, but that means you fix them before they cause a crash.
How to Enable Strict Mode
Enabling strict mode takes one line in your tsconfig.json.
{
"compilerOptions": {
"strict": true
}
}
Enter fullscreen mode Exit fullscreen mode
That is it. This one setting turns on 8 different checks at the same time.
You can also turn it on temporarily from the command line:
tsc --strict
Enter fullscreen mode Exit fullscreen mode
What Does strict: true Actually Turn On?
When you set "strict": true, TypeScript enables these 8 flags automatically:
strictNullChecks
Stops you from using null or undefined where a real value is expected
noImplicitAny
Forces you to add types when TypeScript cannot figure them out
strictFunctionTypes
Checks that function parameters match the expected types correctly
strictBindCallApply
Makes .bind(), .call(), and .apply() type-safe
strictPropertyInitialization
Makes sure class properties are set in the constructor
noImplicitThis
Stops you from using this when its type is unclear
useUnknownInCatchVariables
Makes the error variable in catch blocks unknown instead of any
alwaysStrict
Adds "use strict" to every compiled JavaScript file
You do not need to set any of these one by one. "strict": true handles all of them.
Note: TypeScript may add new flags to the strict group in future versions. When you upgrade TypeScript, those new flags turn on automatically if you have
"strict": true. This is a good thing. It means your code gets safer with every upgrade.
Why Each Flag Matters (With Code Examples)
1. strictNullChecks — Stop Null Crashes
This is the most important flag. Without it, TypeScript lets you use null and undefined anywhere. This causes runtime crashes.
Without strict:
function getLength(text: string): number {
return text.length; // No error here
}
getLength(null); // Compiles fine. Crashes at runtime.
Enter fullscreen mode Exit fullscreen mode
With strict:
function getLength(text: string): number {
return text.length;
}
getLength(null);
// Error: Argument of type 'null' is not assignable
// to parameter of type 'string'.
Enter fullscreen mode Exit fullscreen mode
Now TypeScript forces you to handle the null case before using the value:
function getLength(text: string | null): number {
if (text === null) {
return 0;
}
return text.length; // TypeScript knows text is a string here
}
Enter fullscreen mode Exit fullscreen mode
2. noImplicitAny — No Hidden any Types
Without this flag, TypeScript quietly gives some values the type any when it cannot figure out the type. any turns off type checking for that value. It defeats the whole point of using TypeScript.
Without strict:
function processItems(items) { // items is silently 'any'
items.forEach(item => {
console.log(item.name); // No type checking at all
});
}
Enter fullscreen mode Exit fullscreen mode
With strict:
function processItems(items) {
// Error: Parameter 'items' implicitly has an 'any' type.
}
Enter fullscreen mode Exit fullscreen mode
Now you must add a type:
function processItems(items: string[]): void {
items.forEach(item => {
console.log(item); // TypeScript checks this correctly
});
}
Enter fullscreen mode Exit fullscreen mode
3. strictPropertyInitialization — Class Properties Must Be Set
Without this flag, you can declare a class property and never set it. Then it is undefined at runtime and causes bugs.
Without strict:
class User {
name: string; // Never set in constructor
greet() {
console.log(this.name.toUpperCase()); // Crashes at runtime
}
}
Enter fullscreen mode Exit fullscreen mode
With strict:
class User {
name: string;
// Error: Property 'name' has no initializer and is not
// definitely assigned in the constructor.
}
Enter fullscreen mode Exit fullscreen mode
Now you must either set it in the constructor or mark it as optional:
// Option 1: Set it in the constructor
class User {
name: string;
constructor(name: string) {
this.name = name;
}
}
// Option 2: Mark it optional with a default
class User {
name: string = "Guest";
}
// Option 3: Mark it as possibly undefined
class User {
name?: string;
}
Enter fullscreen mode Exit fullscreen mode
4. useUnknownInCatchVariables — Safe Error Handling
In older TypeScript, the error variable inside a catch block had the type any. That meant you could call any method on it without checking. This could crash.
Without strict:
try {
doSomething();
} catch (error) {
console.log(error.message); // error is 'any', no check done
}
Enter fullscreen mode Exit fullscreen mode
With strict:
try {
doSomething();
} catch (error) {
console.log(error.message);
// Error: 'error' is of type 'unknown'.
}
Enter fullscreen mode Exit fullscreen mode
Now you must check what kind of error it is before using it:
try {
doSomething();
} catch (error) {
if (error instanceof Error) {
console.log(error.message); // Safe to use
} else {
console.log("Unknown error occurred");
}
}
Enter fullscreen mode Exit fullscreen mode
5. strictBindCallApply — Type-Safe Function Methods
This flag makes .call(), .bind(), and .apply() check that you pass the right argument types.
Without strict:
function greet(name: string): string {
return `Hello, ${name}`;
}
greet.call(undefined, 42); // Wrong type, but no error
Enter fullscreen mode Exit fullscreen mode
With strict:
function greet(name: string): string {
return `Hello, ${name}`;
}
greet.call(undefined, 42);
// Error: Argument of type 'number' is not assignable
// to parameter of type 'string'.
Enter fullscreen mode Exit fullscreen mode
6. noImplicitThis — Clear this Typing
Without this flag, using this inside a regular function is allowed even when TypeScript does not know what this points to.
Without strict:
function printName() {
console.log(this.name); // 'this' is implicitly 'any'
}
Enter fullscreen mode Exit fullscreen mode
With strict:
function printName() {
console.log(this.name);
// Error: 'this' implicitly has type 'any' because it does
// not have a type annotation.
}
Enter fullscreen mode Exit fullscreen mode
Fix it by adding an explicit this type:
function printName(this: { name: string }) {
console.log(this.name); // TypeScript knows the shape of 'this'
}
Enter fullscreen mode Exit fullscreen mode
Two Extra Flags Worth Adding
These two flags are NOT included in strict: true. But they are worth turning on for even safer code.
noUncheckedIndexedAccess
When you access an array item by index, TypeScript normally assumes the item exists. This flag makes it return T | undefined instead.
const names: string[] = ["Alice", "Bob"];
// Without noUncheckedIndexedAccess
const first: string = names[0]; // TypeScript thinks this is always a string
// With noUncheckedIndexedAccess
const first: string | undefined = names[0]; // Safer, might be undefined
if (first !== undefined) {
console.log(first.toUpperCase()); // Now safe to use
}
Enter fullscreen mode Exit fullscreen mode
noImplicitOverride
This flag makes you add the override keyword when you override a method in a subclass. It prevents silent bugs when the parent class changes.
class Animal {
makeSound() {
console.log("...");
}
}
// Without noImplicitOverride: no error even if parent renames the method
class Dog extends Animal {
makeSound() { // Silently breaks if parent renames makeSound()
console.log("Woof");
}
}
// With noImplicitOverride: you must write override
class Dog extends Animal {
override makeSound() { // Clear intent, compiler verifies parent has this
console.log("Woof");
}
}
Enter fullscreen mode Exit fullscreen mode
Add them to your tsconfig.json alongside strict:
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true
}
}
Enter fullscreen mode Exit fullscreen mode
The Full Recommended Strict Config
Here is the complete set of strict options we recommend for all new TypeScript projects:
{
"compilerOptions": {
"target": "ES2022",
"module": "CommonJS",
"strict": true,
"noUncheckedIndexedAccess": true,
"noImplicitOverride": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true
}
}
Enter fullscreen mode Exit fullscreen mode
Here is what the extra flags do:
Flag What It DoesnoUnusedLocals
Errors on variables that are declared but never used
noUnusedParameters
Errors on function parameters that are never used
noImplicitReturns
Errors when a function does not return a value on all paths
What the Same Code Looks Like Without and With Strict Mode
Here is a real example. This function has two silent bugs without strict mode.
Without strict mode (no errors shown):
function getUserCity(user) {
return user.address.city;
}
const city = getUserCity(null);
console.log(city.toUpperCase());
Enter fullscreen mode Exit fullscreen mode
This code compiles with no errors. But it will crash at runtime because:
-
usercould benull -
user.addresscould beundefined -
citycould beundefined
With strict mode (all bugs caught at compile time):
// Error on line 1: Parameter 'user' implicitly has an 'any' type.
function getUserCity(user) {
return user.address.city;
}
Enter fullscreen mode Exit fullscreen mode
TypeScript stops you right away. You now write a safe version:
type Address = {
city: string;
};
type User = {
address: Address | null;
};
function getUserCity(user: User | null): string {
if (user === null || user.address === null) {
return "Unknown";
}
return user.address.city;
}
const city = getUserCity(null);
console.log(city.toUpperCase()); // Always safe
Enter fullscreen mode Exit fullscreen mode
How to Enable Strict Mode on an Existing Project
If you are adding TypeScript to an older project, turning on strict: true all at once can show hundreds of errors. That is overwhelming.
Do it step by step instead.
Step 1: Keep strict off. Turn on flags one at a time.
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true
}
}
Enter fullscreen mode Exit fullscreen mode
Step 2: Fix all the errors from that flag. Commit your changes.
Step 3: Add the next flag.
{
"compilerOptions": {
"strict": false,
"noImplicitAny": true,
"strictNullChecks": true
}
}
Enter fullscreen mode Exit fullscreen mode
Step 4: Keep going until all 8 flags are on. Then replace them all with "strict": true.
Here is a good order to follow when migrating:
Step Flag to Enable Why This Order 1noImplicitAny
Easiest to fix, forces you to add types
2
strictNullChecks
Most impactful, stops null crashes
3
strictPropertyInitialization
Fixes class property bugs
4
strictFunctionTypes
Catches function type mismatches
5
strictBindCallApply
Usually few errors, easy to fix
6
noImplicitThis
Quick fixes with this annotations
7
useUnknownInCatchVariables
Makes catch blocks safer
8
alwaysStrict
Adds "use strict" to JS output
Does Strict Mode Change the JavaScript Output?
No. Strict mode is a compile-time feature only.
All the checks happen when you run tsc. The compiled JavaScript output is identical whether strict mode is on or off.
The only exception is alwaysStrict. That flag adds "use strict" at the top of every compiled JavaScript file. But that is a JavaScript directive, not a TypeScript type change.
Common Errors You Will See After Enabling Strict Mode
Here are the errors developers hit most often after turning on strict mode.
“Object is possibly null”
const el = document.getElementById("app");
el.innerHTML = "Hello";
// Error: 'el' is possibly 'null'.
// Fix:
const el = document.getElementById("app");
if (el !== null) {
el.innerHTML = "Hello";
}
Enter fullscreen mode Exit fullscreen mode
“Parameter implicitly has an ‘any’ type”
function double(n) { // Error
return n * 2;
}
// Fix:
function double(n: number): number {
return n * 2;
}
Enter fullscreen mode Exit fullscreen mode
“Property has no initializer”
class Cart {
items: string[]; // Error
}
// Fix:
class Cart {
items: string[] = [];
}
Enter fullscreen mode Exit fullscreen mode
“Not all code paths return a value”
function grade(score: number) {
if (score >= 90) {
return "A";
}
// Error: Function lacks ending return statement
}
// Fix:
function grade(score: number): string {
if (score >= 90) {
return "A";
}
return "B";
}
Enter fullscreen mode Exit fullscreen mode
FAQ
Q: Does strict mode make TypeScript harder to use?
At first, yes. You will see more errors. But each error points to a real bug. Over time, your code becomes more reliable and easier to maintain.
Q: Can I turn off just one strict flag?
Yes. You can override any individual flag even with strict: true. For example, if you want everything except alwaysStrict, set it to false after enabling strict:
{
"compilerOptions": {
"strict": true,
"alwaysStrict": false
}
}
Enter fullscreen mode Exit fullscreen mode
Q: Should I use strict mode on a team project?
Yes. Always. Agree on it at the start of the project so the whole team works with the same rules.
Q: Is strict: true the default?
No. TypeScript defaults to strict: false. You have to opt in. This is why you should always set it manually.
Q: Does strict mode slow down compilation?
A tiny bit. More checks take more time. But the difference is not noticeable on most projects.
Q: What is the difference between strict and strictNullChecks?
strictNullChecks is one of the 8 checks inside strict: true. Setting strict: true includes strictNullChecks plus 7 other checks. Always use strict: true instead of setting individual flags one by one on new projects.
What You Learned
-
"strict": trueintsconfig.jsonturns on 8 safety checks at once -
strictNullChecksstops null crashes before they happen at runtime -
noImplicitAnyforces you to add proper types everywhere -
strictPropertyInitializationcatches unset class properties -
useUnknownInCatchVariablesmakes error handling safer - Add
noUncheckedIndexedAccessandnoImplicitOverridefor even more safety - On new projects, always start with
strict: true - On existing projects, enable each flag one at a time and fix errors before adding the next
Sources: TypeScript TSConfig Reference | TypeScript Official Docs — Strict Mode

답글 남기기