Strict mode options
Learn the nine checks strict turns on, the extra flags like noUncheckedIndexedAccess worth adding, and how to raise strictness in a project one step at a time.
- 01Name what strict turns onList the checks in the strict group, say what each one reports, and turn one off on its own.
- 02Add the extra checksUse noUncheckedIndexedAccess, exactOptionalPropertyTypes, and noImplicitOverride, and fix the errors they find.
- 03Raise strictness safelyTurn on checks one at a time in an existing project, fixing each list of errors before the next.
One setting, many checks
A shop page looks up a product's price by name. The code below has three problems. With strict checks on, which is how this page checks every example unless it says otherwise, TypeScript marks all three, on purpose here:
type Product = { name: string; price: number };const products: Product[] = [{ name: "Tea", price: 3 }]; function priceOf(name) { const product = products.find((item) => item.name === name); return product.price;} try { console.log(priceOf("Cake"));} catch (error) { console.log(error.message);}Line 1 says what a Product is, and line 2 makes a list with only tea in it. Line 4 starts priceOf, line 5 looks for the product with find, and line 6 returns its price. Line 10 asks for cake, which isn't there, so line 6 throws a TypeError. The catch block on lines 11 and 12 catches it (the try...catch lesson covers this) and prints Cannot read properties of undefined (reading 'price'). The three marks:
- Line 4,
Parameter 'name' implicitly has an 'any' type: nothing says whatnameholds. - Line 6,
'product' is possibly 'undefined':findgives backundefinedwhen nothing matches. This is the crash. - Line 12,
'error' is of type 'unknown': code can throw anything, not only errors, so TypeScript won't let you readmessagebefore you check.
In Setting up a project you turned on "strict": true and saw it catch the first two. What you didn't see is that strict isn't one check. Each of these three errors comes from a different check, and each check has its own name, called a flag: a setting in compilerOptions that is true or false. strict is a shortcut that turns on nine of them. Other flags aren't in the group, and a project adds them by name:
{ "compilerOptions": { "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noImplicitOverride": true }}Line 3 turns on the strict group. Lines 4 to 6 add three checks from outside it, which this lesson covers one by one. In TypeScript 5.9, every flag here is false unless something turns it on. (TypeScript 6.0 and later turn strict on by default, as Setting up a project mentioned, but writing it keeps every version the same.)
"strict": true turns on the nine checks in the left window at once. The checks on the right aren't in the group, so you add each one by name.When a new building is fitted out, the owner can tick one box for the full safety package. Alarms, sprinklers, and exit signs all arrive together. The owner can still cross out one item for now. Some useful things, like fire blankets in the kitchen, aren't in the package at all, so the owner orders them separately.
- In real life: You tick "full safety package" on the form
- In TypeScript: You write
"strict": true - In real life: Alarms, sprinklers, and exit signs all get fitted
- In TypeScript:
noImplicitAny,strictNullChecks, and seven more turn on - In real life: You cross out the sprinklers for one room you'll finish later
- In TypeScript: You add
"strictNullChecks": falseafter strict - In real life: Fire blankets aren't in the package; you order them by name
- In TypeScript: You add
noUncheckedIndexedAccessby name
strict is one switch for a group of checks. Each check is a flag with its own name, and a flag you write yourself wins over the group. Some of the most useful checks, like noUncheckedIndexedAccess, aren't in the group, so you add them one by one.
What strict turns on
Here is the price lookup again. The code never changes; only the settings do. Turn on one check at a time and watch which line each one marks:
type Product = { name: string; price: number };const products: Product[] = [{ name: "Tea", price: 3 }]; function priceOf(name) { const product = products.find((item) => item.name === name); return product.price;} try { console.log(priceOf("Cake"));} catch (error) { console.log(error.message);}No errors{
"compilerOptions": {
"strict": false
}
}Cannot read properties of undefined (reading 'price')No errors at all. name on line 4 is quietly any, find is trusted to always find something, and error on line 11 is any too. The code runs and prints the message from line 12, because there is no cake.
Start with strict: false: no errors, even though the code crashes. Each of the next three buttons turns on one flag and gets exactly one error. strict: true gets all three. Notice that line 12's message changes. With only useUnknownInCatchVariables on, it's Property 'message' does not exist on type 'unknown'; with strictNullChecks on as well, TypeScript says it more directly. The last button keeps strict on and turns one flag off. The order in the file doesn't matter: a flag you name always wins over the group.
That last button is how a project keeps strict on while it isn't ready for one or two checks yet:
{ "compilerOptions": { "strict": true, "strictNullChecks": false, "strictPropertyInitialization": false }}Line 3 turns on the whole group. Lines 4 and 5 turn two of its checks off again. Everything else in the group stays on, and any check a future TypeScript adds to strict turns on too. The TypeScript documentation says this plainly: a new version may add stricter checks under strict, so an upgrade can bring new errors.
In TypeScript 5.9 the group has nine flags. Read each row of the table as: this flag, what it reports, and where this lesson shows it. You've met the first two before, in any, unknown & never and null and undefined.
| The flag | What it reports | Where you see it |
|---|---|---|
noImplicitAny | A parameter or variable with no type written, whose type TypeScript can't work out. | Line 4 of the price lookup: function priceOf(name). |
strictNullChecks | Code that uses a value that might be null or undefined without checking first. | Line 6: product.price, after a find that might find nothing. |
useUnknownInCatchVariables | Using the error in a catch block before checking what it is. | Line 12: error.message. |
strictPropertyInitialization | A class field that a new object might not get a value for. | count: number in CartBadge. |
strictFunctionTypes | A function that needs a narrower parameter than its caller promises to pass. | logPosition stored as a ClickHandler. |
strictBindCallApply | Wrong arguments passed through a function's call, apply, or bind. | applyDiscount.call(null, 20). |
noImplicitThis | this in a function where TypeScript can't tell what this is. | this.label in showLabel. |
strictBuiltinIteratorReturn | Treating the last result of a built-in iterator as anything, when it is really undefined. | Not shown. It matters when you call next() on an iterator yourself. |
alwaysStrict | Code that JavaScript's strict mode doesn't allow, in every file. It also adds "use strict" to the JavaScript of files that aren't modules; modules are in strict mode already. | Not shown. Every example here is a module. |
Four quieter checks inside strict
noImplicitAny and strictNullChecks find the most errors. Four others find fewer, but each one catches a real kind of bug. Each example below is checked with strict on, and each has one error on purpose. First, a class field that never gets a value:
class CartBadge { count: number; label = "Cart";} const badge = new CartBadge();console.log(`${badge.label}: ${badge.count}`);Line 2 says every CartBadge has a count that is a number, but nothing ever gives it one. Line 3 is fine, because label starts as "Cart". strictPropertyInitialization marks line 2: Property 'count' has no initializer and is not definitely assigned in the constructor, which means "no starting value, and the constructor doesn't set one either". Line 7 prints Cart: undefined. (Classes in TypeScript covers fields.)
type ClickHandler = (event: Event) => void; function logPosition(event: MouseEvent) { console.log(event.clientX);} const handler: ClickHandler = logPosition;Line 1 describes a handler that may be given any Event, like a key press. Line 3's logPosition only works with a MouseEvent, because line 4 reads clientX, the pointer's position. Line 7 tries to store it as a ClickHandler. strictFunctionTypes marks it: Type '(event: MouseEvent) => void' is not assignable to type 'ClickHandler'. Called with a key press, line 4 would print undefined. The next lines of the message list the missing properties.
function applyDiscount(total: number, percent: number) { return total - (total * percent) / 100;} console.log(applyDiscount.call(null, 20));Every function has a call method whose first argument is the value for this and whose others go to the function (Methods and this covers it). Line 5 passes only one of the two numbers. strictBindCallApply checks those arguments like a normal call, so it says Expected 3 arguments, but got 2: the this value plus two numbers. Without it, line 5 would quietly print NaN, as it does when you run it.
const badge = { label: "Cart", show: showLabel,}; function showLabel() { return `Label: ${this.label}`;}console.log(badge.show());Lines 1 to 4 make a badge whose show is the function on line 6. Line 7 reads this.label, but a plain function can be called on anything, so TypeScript can't know what this is. noImplicitThis marks it: 'this' implicitly has type 'any' because it does not have a type annotation. Line 9 does print Label: Cart; the check is about the calls TypeScript can't see. The fix is a this parameter, from this in TypeScript.
noUncheckedIndexedAccess: the item might not be there
Strict checks a find that might find nothing. It doesn't check an array index or a key that might not be there. You met the flag that does in Index signatures and Arrays and tuples. Here it is with the switch in your hands:
const prices: Record<string, number> = { tea: 3, cake: 4 }; const jam = prices["jam"];// ^?console.log(jam.toFixed(2));falseconst jam: numberNo errorsthrows a TypeErrorWith the flag off, the query on line 4 says jam is a number. TypeScript reports nothing, but there is no jam in prices, so line 5 throws a TypeError when it runs.
Line 1 makes a price list with tea and cake. Line 3 reads the price of jam, and the query on line 4 shows its type. With Flag off, jam is a number, and line 5 crashes with no warning. With Flag on, it's number | undefined, and line 5 is marked. With a fallback uses ?? to pick 0 when jam is undefined and prints 0.00 (Nullish coalescing & optional chaining covers ??).
prices has no jam, so prices["jam"] gives undefined. With the flag off, TypeScript still calls it a number. With the flag on, the type says what can really happen.The flag doesn't make every array read harder. It only adds undefined where an item really might be missing:
const cart = ["tea", "cake"];const first = cart[0];// ^?for (const item of cart) { // ^? console.log(item.toUpperCase());}const pair: [string, number] = ["tea", 3];const product = pair[0];// ^?- Line 2 reads
cart[0]. The query on line 3 saysstring | undefined: astring[]can be empty. - Line 4 loops with
for...of, and the query on line 5 saysitemis astring. A loop only visits items that are there (for...of and for...in). Line 6 printsTEAandCAKE. - Line 8 makes a tuple, an array with a fixed length. Line 9 reads index 0, which always exists, so the query on line 10 says
string.
So code that loops, or uses methods like map, rarely notices the flag. Code that picks items by position or by key gets an error wherever it forgot that the item might be missing.
exactOptionalPropertyTypes: left out is not undefined
A property marked with ?, like theme?: "light" | "dark", is optional: an object may leave it out. In JavaScript, leaving a key out and giving it the value undefined are two different objects:
const defaults = { theme: "light", fontSize: 16 };
const leftOut = {};
const setToUndefined = { theme: undefined };
console.log({ ...defaults, ...leftOut }.theme);
console.log({ ...defaults, ...setToUndefined }.theme);
console.log("theme" in setToUndefined);Line 1 holds the defaults. Line 2 leaves theme out; line 3 has a theme key holding undefined. Lines 5 and 6 spread each one over the defaults (Spread and rest covers ...). Line 5 prints light: nothing replaced the default. Line 6 prints undefined: the key was copied, value and all. Line 7 prints true, because the key exists.
{ } over the defaults keeps "light". Spreading { theme: undefined } copies the undefined over it. The two look alike to an optional type, unless exactOptionalPropertyTypes is on.By default, TypeScript treats both the same way: theme?: allows undefined too. exactOptionalPropertyTypes makes ? mean only "may be left out". Try saving the theme in different ways:
type Settings = { theme: "light" | "dark"; fontSize: number };type SavedSettings = { theme?: "light" | "dark"; fontSize?: number }; const defaults: Settings = { theme: "light", fontSize: 16 };const saved: SavedSettings = { theme: undefined };const settings = { ...defaults, ...saved };// ^?console.log(settings.theme);undefinedfalseNo errorsWith the flag off, theme?: also allows undefined, so line 5 is fine. The query on line 7 promises a theme of "light" | "dark", but the spread copies the undefined over the default, and line 8 prints undefined.
With the flag off, line 5 is fine, and the query on line 7 says theme is "light" | "dark". Line 8 prints undefined anyway: the type made a promise the code broke. With the flag on, the same line 5 is marked, and the message ends with with 'exactOptionalPropertyTypes: true', so you know which flag is talking. Leave the theme out, or save a real one, and the error is gone. (Utility types showed the same flag with Partial.)
The flag also changes what you may write into an optional property later:
type Profile = { nickname?: string; bio?: string | undefined }; const profile: Profile = { nickname: "Ash" };profile.nickname = undefined;delete profile.nickname;profile.bio = undefined;- Line 1 makes
nicknameoptional, andbiooptional with| undefinedwritten out. - Line 4 writes
undefinedintonicknameand is marked:Type 'undefined' is not assignable to type 'string' with 'exactOptionalPropertyTypes: true'. - Line 5 removes the key with
delete, which is fine: now it's really left out. - Line 6 writes
undefinedintobio, which is fine, because its type saysundefinedis allowed.
More checks outside strict
A few more flags catch mistakes that aren't about types at all. One is about classes. When a class extends another (Class inheritance), it can replace a method of its parent by giving its own method the same name. TypeScript has a keyword to say you mean it, override, and a flag that makes it required:
class Widget { draw() { return "widget"; }} class CartWidget extends Widget { draw() { return "cart"; }} class BadgeWidget extends Widget { override render() { return "badge"; }}- Lines 1 to 5 make a
Widgetwith adrawmethod. - Line 8 replaces
drawinCartWidgetwithout saying so. WithnoImplicitOverrideon, that's marked:This member must have an 'override' modifier because it overrides a member in the base class 'Widget'. - Line 14 says
override, butWidgethas norender. Maybe it was renamed todrawlast week. TypeScript marks it:This member cannot have an 'override' modifier because it is not declared in the base class 'Widget'.
Together, the two errors keep classes in step with their parents. Once every replaced method says override, renaming the parent's method gets you an error in every child that still uses the old name.
function shippingCost(country: string) { if (country === "IN") { return 0; } else if (country === "US") { return 5; }} console.log(shippingCost("FR"));Lines 2 to 6 return a cost for India and for the US. For any other country the function reaches the end without a return, so line 9 prints undefined. noImplicitReturns marks line 1: Not all code paths return a value.
TypeScript 5.9's tsc --init, the command that writes a new tsconfig.json, turns two extra flags on and lists the rest as comments for you to consider. Read each row as: this flag, what it reports, and what tsc --init does with it.
| The flag | What it reports | Turned on by tsc --init in 5.9? |
|---|---|---|
noUncheckedIndexedAccess | Using an item read by index or by a key the type can't promise, without checking it exists. | Yes, it's on. |
exactOptionalPropertyTypes | Writing undefined into an optional property that doesn't list undefined. | Yes, it's on. |
noImplicitOverride | A class method that replaces the parent's method without the word override. | Listed, but commented out. |
noImplicitReturns | A function where some paths return a value and others fall off the end. | Listed, but commented out. |
noFallthroughCasesInSwitch | A case with code that runs on into the next case with no break. | Listed, but commented out. |
noPropertyAccessFromIndexSignature | Reading a key that only an index signature allows with a dot, like env.apiUrl. | Listed, but commented out. |
noUnusedLocals, noUnusedParameters | Variables and parameters that are never used. | Listed, but commented out. |
Turning strictness up gradually
A new project should start with strict on. An older project with strict off can have hundreds of errors waiting. Turning everything on at once gives one huge change that's hard to finish. The safer path is one check at a time: turn it on, fix its errors, merge the change, then the next. Step through it on a small user list:
type User = { name: string; email?: string }; const users: User[] = [ { name: "Asha", email: "asha@example.com" }, { name: "Ravi" },]; function emailDomain(user) { return user.email.split("@")[1];} console.log(emailDomain(users[0]));No errors{
"compilerOptions": {
"strict": false
}
}example.comThe project starts with strict off. No errors, and the code prints example.com. Ravi has no email, but nothing reads his yet.
Line 1 says a User may have an email, and line 5 is a user without one. Line 8 starts emailDomain, line 9 reads the part of the email after the @, and line 12 calls it. Steps 2, 4, and 7 each turn on one check and get one error. Steps 3, 5, and 8 fix it. Step 4 found a real bug: Ravi has no email, and line 9 would crash on him. Step 6 swaps the two flags for strict: true and finds nothing new in this code.
strict: true added nothing new in this code.A few habits make this work in a real project:
- Start with
noImplicitAny, thenstrictNullChecks. They find the most errors, and the rest of the group is usually quick after them. - Or turn on
strictand switch off the flags that aren't ready yet, as in thetsconfig.jsonabove. Then deleting onefalseline is the whole next step. - Merge each step on its own, so nobody waits on a change with hundreds of fixes.
- Add the extra flags last.
noUncheckedIndexedAccessoften finds the most errors of all in code that reads arrays by index.
Migrating JavaScript to TypeScript, later in this course, uses the same steps while moving a whole project from .js files to TypeScript.
The strict settings of a shop project
Here is a complete tsconfig.json for a shop's frontend built with a bundler like Vite. The output settings come from the next lesson; this one is about lines 6 to 11:
{ "compilerOptions": { "target": "es2022", "module": "esnext", "moduleResolution": "bundler", "strict": true, "noUncheckedIndexedAccess": true, "exactOptionalPropertyTypes": true, "noImplicitOverride": true, "noImplicitReturns": true, "noFallthroughCasesInSwitch": true, "noEmit": true }, "include": ["src"]}- Line 6 turns on the strict group.
- Lines 7 and 8 add the two checks
tsc --initalso turns on: an item that might be missing, andundefinedin an optional property. - Lines 9 to 11 add three checks that catch mistakes in classes, returns, and
switchstatements. - Line 12 says only check, don't write files, because the bundler builds the JavaScript.
Now sort the lines below by which setting reports them. Each one is checked on its own, with and without that setting.
function total(price) { return price * 2; }const sizes = ["S", "M"]; const big = sizes.find((size) => size === "L"); big.length;const sizes = ["S", "M"]; sizes[2].toLowerCase();const stock: Record<string, number> = { tea: 5 }; stock.jam.toFixed(0);const order: { coupon?: string } = { coupon: undefined };const profile: { nickname?: string } = {}; profile.nickname = undefined;class Page { load() {} } class CartPage extends Page { load() {} }class Button { click() {} } class BuyButton extends Button { click() {} }
Sort each line by the setting that reports it. Each line gets an error with that setting on, and none with it off.
Common mix-ups
The override keyword checks something even with the flag off. Here noImplicitOverride isn't set:
class Page { load() { return "page"; }} class CartPage extends Page { override reload() { return "cart"; }}Line 8 says override reload(), but Page only has load. TypeScript marks it anyway and even asks Did you mean 'load'?. Writing override is always checked. What the flag adds is that leaving it out is an error too.
- "strict turns on every check TypeScript has." No. It turns on a group of nine in TypeScript 5.9.
noUncheckedIndexedAccess,exactOptionalPropertyTypes, andnoImplicitOverrideare outside it. - "Writing strict: true and strictNullChecks: false is a contradiction." No. It means "the whole group, except this one". A flag you write yourself wins over the group, wherever it sits in the file.
- "noUncheckedIndexedAccess makes every array read a chore." No.
for...ofloops, methods likemap, and fixed tuple indexes are unchanged. Only reads that might miss getundefined. - "A key set to undefined is the same as a key left out." No. A spread copies the
undefined, andinfinds the key.exactOptionalPropertyTypeskeeps the two apart. - "Turning on a stricter flag changes what my code does." No. The checks only change what TypeScript reports. The one exception is
alwaysStrict: in a file that isn't a module, it also adds"use strict"to the JavaScript. A module is in strict mode already, so nothing changes there. - "Once strict is on, upgrading TypeScript can't add errors." No. New versions may add checks to the group, so an upgrade can bring new errors. Turning one off by name is the way out while you fix them.
Practice exercises
Every exercise is TypeScript and lists the settings it's checked with under the code. Press Edit & run to change the code: the errors update as you type. Try a guess first, then use the hints.
With strict on, TypeScript marks line 4 of this code. Which check in the strict group is reporting it? Then fix it without turning the check off.
try {
JSON.parse("{ broken");
} catch (error) {
console.log(error.name);
}try { JSON.parse("{ broken");} catch (error) { if (error instanceof Error) { console.log(error.name); }}useUnknownInCatchVariables makes error the type unknown, so line 4 can't read name yet. Checking error instanceof Error first narrows it to an Error, and the code prints SyntaxError.
What type does firstSize get? Guess first, then point at it, or press Edit & run and add a // ^? line under it.
const sizes = ["S", "M", "L"];const firstSize = sizes[0];const sizes = ["S", "M", "L"];const firstSize = sizes[0];// ^?A string[] might be empty, so with the flag on, sizes[0] is string | undefined. The query on line 3 shows const firstSize: string | undefined.
A search box shows its top result in capitals. With noUncheckedIndexedAccess on, TypeScript marks line 4, and line 8 really throws. Fix line 4 without turning the flag off. What does line 8 print then?
const results = ["Green tea", "Black tea"]; function topResult(list: string[]) { return list[0].toUpperCase();} console.log(topResult(results));console.log(topResult([]));const results = ["Green tea", "Black tea"]; function topResult(list: string[]) { return list[0]?.toUpperCase() ?? "No results";} console.log(topResult(results));console.log(topResult([]));list[0]?.toUpperCase() stops at a missing first result and gives undefined, and ?? "No results" replaces that. Line 7 prints GREEN TEA, and line 8 prints No results instead of throwing.
The saved settings keep the font size the reader picked, but line 5 is marked. Fix it so the default theme survives. What does the fixed code print?
type Settings = { theme: "light" | "dark"; fontSize: number };type SavedSettings = { theme?: "light" | "dark"; fontSize?: number }; const defaults: Settings = { theme: "light", fontSize: 16 };const saved: SavedSettings = { theme: undefined, fontSize: 18 };const settings = { ...defaults, ...saved };console.log(`${settings.theme} ${settings.fontSize}`);type Settings = { theme: "light" | "dark"; fontSize: number };type SavedSettings = { theme?: "light" | "dark"; fontSize?: number }; const defaults: Settings = { theme: "light", fontSize: 16 };const saved: SavedSettings = { fontSize: 18 };const settings = { ...defaults, ...saved };console.log(`${settings.theme} ${settings.fontSize}`);With no theme key in saved, the spread keeps the default "light" and only replaces the font size. It prints light 18. The starter printed undefined 18.
This example has noImplicitOverride on. Fix line 8 so TypeScript knows the replacement is on purpose. Which word did you add?
class Widget { draw() { return "widget"; }} class CartWidget extends Widget { draw() { return "cart (3)"; }} console.log(new CartWidget().draw());class Widget { draw() { return "widget"; }} class CartWidget extends Widget { override draw() { return "cart (3)"; }} console.log(new CartWidget().draw());override draw() says on purpose that CartWidget replaces Widget's draw. noImplicitOverride is satisfied, and if Widget.draw is ever renamed, line 8 gets an error. It prints cart (3).
Strict marks two lines, and the starter prints 18 and then throws on "CAKE5". Fix both errors without changing the settings. An unknown code should leave the total as it is. What does the fixed code print for "CAKE5"?
type Coupon = { code: string; percent: number };const coupons: Coupon[] = [{ code: "TEA10", percent: 10 }]; function discounted(total, code: string) { const coupon = coupons.find((item) => item.code === code); return total - (total * coupon.percent) / 100;} console.log(discounted(20, "TEA10"));console.log(discounted(20, "CAKE5"));type Coupon = { code: string; percent: number };const coupons: Coupon[] = [{ code: "TEA10", percent: 10 }]; function discounted(total: number, code: string) { const coupon = coupons.find((item) => item.code === code); if (!coupon) return total; return total - (total * coupon.percent) / 100;} console.log(discounted(20, "TEA10"));console.log(discounted(20, "CAKE5"));total: number fixes the noImplicitAny error. if (!coupon) return total; handles a code that matches nothing, so coupon can't be undefined on the next line. It prints 18 for TEA10 and 20 for CAKE5.
Check your understanding
Each question names the settings it assumes. The quiz shows its code without the checker, so the error list doesn't give the answers away.
Question 1 of 7What does
"strict": truein tsconfig.json do?Choose an answer to see the explanation.
Question 2 of 7With
"strict": trueand"strictNullChecks": false, what happens with this code?Read the code, then predictconst sizes = ["S", "M"]; const big = sizes.find((size) => size === "L"); console.log(big.length);Choose an answer to see the explanation.
Question 3 of 7With
noUncheckedIndexedAccesson, what type doessecondget?Read the code, then predictconst cart = ["tea", "cake"]; const second = cart[1];Choose an answer to see the explanation.
Question 4 of 7With
noUncheckedIndexedAccesson, does this loop get an error?Read the code, then predictconst cart = ["tea", "cake"]; for (const item of cart) { console.log(item.toUpperCase()); }Choose an answer to see the explanation.
Question 5 of 7With
exactOptionalPropertyTypeson, which line does TypeScript mark?Read the code, then predicttype Profile = { nickname?: string }; const a: Profile = {}; const b: Profile = { nickname: "Ash" }; const c: Profile = { nickname: undefined };Choose an answer to see the explanation.
Question 6 of 7Which setting makes TypeScript require the word
overrideon a method that replaces the parent's?Choose an answer to see the explanation.
Question 7 of 7A big project has strict off and you want it on. What's a good first step?
Choose an answer to see the explanation.
Key takeaways
strictturns on a group of nine checks in TypeScript 5.9, each a flag with its own name, likenoImplicitAnyandstrictNullChecks.- A flag you write yourself wins over the group:
strict: truewithstrictNullChecks: falsekeeps the rest on. noUncheckedIndexedAccessaddsundefinedto reads by index or key that might miss. Loops and tuples are unchanged.exactOptionalPropertyTypesmakes?mean "may be left out", not "may beundefined".noImplicitOverride,noImplicitReturns, andnoFallthroughCasesInSwitchcatch mistakes in classes, returns, andswitch.- In an existing project, turn checks on one at a time and fix each list before the next.
Remember the one-liner.strict is a group of named checks: turn on the group, add the extras by name, and switch off only what you're still fixing.
Coming next: target, lib & module. It covers the other half of tsconfig.json: which JavaScript tsc writes, which built-in types it knows, and how imports are found.