0
0
Typescriptprogramming~15 mins

Nullish coalescing with types in Typescript - Deep Dive

Choose your learning style9 modes available
Overview - Nullish coalescing with types
What is it?
Nullish coalescing is a way to provide a default value when a variable is null or undefined. In TypeScript, it helps handle cases where a value might be missing without confusing other falsy values like 0 or empty string. This operator looks like two question marks (??) and returns the right side only if the left side is null or undefined. It works well with TypeScript's type system to keep code safe and clear.
Why it matters
Without nullish coalescing, developers often use or (||) to provide defaults, but that treats many valid values like 0 or empty string as missing, causing bugs. Nullish coalescing solves this by only treating null or undefined as missing. This makes programs more reliable and easier to understand, especially when working with typed data where knowing exactly what values are allowed is important.
Where it fits
Before learning this, you should understand basic TypeScript types and how JavaScript handles null, undefined, and falsy values. After this, you can explore advanced TypeScript features like optional chaining, strict null checks, and type narrowing to write safer and cleaner code.
Mental Model
Core Idea
Nullish coalescing returns a default only when a value is truly missing (null or undefined), not just falsy.
Think of it like...
It's like checking if a mailbox is empty or missing before deciding to deliver a letter to a neighbor; you only act if the mailbox is truly absent, not if it's just empty or has junk mail.
Value ?? Default
  │       │
  │       └─ Used if Value is null or undefined
  └─ Used if Value is anything else (including 0, '', false)
Build-Up - 7 Steps
1
FoundationUnderstanding null and undefined
🤔
Concept: Learn what null and undefined mean in TypeScript and how they differ from other values.
In TypeScript, null means a variable explicitly has no value, while undefined means a variable hasn't been assigned a value yet. Both represent absence but are different types. For example: let a: number | null = null; let b: number | undefined; Here, 'a' is set to null, 'b' is undefined because it has no assigned value.
Result
You can distinguish between variables that are missing a value (null or undefined) and those that have actual values.
Understanding these two absence states is key because nullish coalescing only treats these as missing, not other falsy values.
2
FoundationFalsy values vs nullish values
🤔
Concept: Differentiate falsy values like 0, '', false from nullish values null and undefined.
JavaScript treats 0, empty string (''), and false as falsy, meaning they behave like false in conditions. But they are valid values, not absence. Null and undefined mean no value at all. For example: const x = 0; if (!x) { console.log('Falsy'); } // prints 'Falsy' But 0 is a meaningful number, not missing.
Result
You know that falsy does not mean missing, which is important for choosing the right defaulting method.
Recognizing this difference prevents bugs where valid values are mistaken for missing ones.
3
IntermediateUsing || operator for defaults
🤔
Concept: Learn how the logical OR operator provides defaults but treats all falsy values as missing.
Before nullish coalescing, developers used || to give default values: const val = input || 'default'; This means if input is falsy (0, '', false, null, undefined), 'default' is used. But this can wrongly replace valid values like 0 or ''.
Result
Defaults are applied too broadly, sometimes hiding real values.
Knowing this limitation motivates the need for a better operator that only treats null or undefined as missing.
4
IntermediateIntroducing nullish coalescing operator ??
🤔Before reading on: do you think ?? treats 0 or empty string as missing? Commit to yes or no.
Concept: Nullish coalescing (??) returns the right side only if the left side is null or undefined, preserving other falsy values.
Example: const val1 = 0 ?? 42; // val1 is 0 const val2 = null ?? 42; // val2 is 42 const val3 = '' ?? 'default'; // val3 is '' This means 0 and '' are kept as valid values, unlike with ||.
Result
You get correct defaults only when values are truly missing.
Understanding this operator helps write clearer, bug-free code that respects valid falsy values.
5
IntermediateTypeScript type narrowing with ??
🤔Before reading on: does ?? affect TypeScript's understanding of variable types? Commit to yes or no.
Concept: Using ?? helps TypeScript narrow types by excluding null and undefined after the operator.
Example: function greet(name: string | null | undefined) { const safeName = name ?? 'Guest'; // safeName is now string without null or undefined console.log(`Hello, ${safeName}`); } TypeScript knows safeName cannot be null or undefined here.
Result
TypeScript can safely assume variables after ?? are not nullish, reducing errors.
Knowing this improves type safety and reduces the need for extra checks.
6
AdvancedCombining ?? with optional chaining
🤔Before reading on: can you use ?? with optional chaining to safely access nested properties? Commit to yes or no.
Concept: You can combine ?? with optional chaining (?.) to handle deeply nested values that might be missing.
Example: const user = { profile: { age: 0 } }; const age = user.profile?.age ?? 18; Here, age is 0, which is valid, so ?? does not replace it with 18. Optional chaining safely accesses age without errors if profile is missing.
Result
You get safe access and correct defaults in complex objects.
Understanding this combination helps write concise, safe code for real-world data.
7
ExpertTypeScript strictNullChecks and ?? behavior
🤔Before reading on: does enabling strictNullChecks change how ?? works? Commit to yes or no.
Concept: With strictNullChecks enabled, TypeScript enforces null and undefined handling, making ?? more powerful and type-safe.
strictNullChecks means variables cannot be null or undefined unless explicitly allowed. Using ?? then clearly separates nullable types: let val: string | null = null; const result = val ?? 'default'; TypeScript knows result is string, not null. Without strictNullChecks, this safety is weaker.
Result
You get stronger type guarantees and fewer runtime errors.
Knowing this helps configure TypeScript for maximum safety and leverage ?? fully.
Under the Hood
At runtime, the nullish coalescing operator (??) evaluates the left operand first. If it is neither null nor undefined, it returns that value immediately. Otherwise, it evaluates and returns the right operand. This differs from || which returns the right operand for any falsy left operand. TypeScript's compiler uses this behavior to narrow types by excluding null and undefined after ??, enabling safer code without extra checks.
Why designed this way?
JavaScript originally used || for defaults, but it treated many valid values as missing, causing bugs. Nullish coalescing was introduced to fix this by only treating null and undefined as missing. TypeScript adopted this to improve type safety and developer experience. The design balances simplicity and correctness, avoiding breaking existing code while adding precise defaulting.
┌───────────────┐
│ Evaluate Left │
└──────┬────────┘
       │
       ▼
┌───────────────┐   No   ┌───────────────┐
│ Is Left null  │──────▶│ Return Left    │
│ or undefined? │       └───────────────┘
└──────┬────────┘
       │ Yes
       ▼
┌───────────────┐
│ Return Right  │
└───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does ?? treat 0 as missing and replace it with the default? Commit to yes or no.
Common Belief:Some think ?? treats all falsy values like 0, '', or false as missing and replaces them.
Tap to reveal reality
Reality:?? only treats null and undefined as missing; 0, '', and false are kept as valid values.
Why it matters:Believing this causes developers to avoid ?? and use ||, leading to bugs where valid values are overwritten.
Quick: Does using ?? always guarantee a non-nullish type in TypeScript? Commit to yes or no.
Common Belief:Some believe that after ??, the result can never be null or undefined in all cases.
Tap to reveal reality
Reality:If the right side of ?? can be null or undefined, the result can still be nullish; only the left side is checked.
Why it matters:Assuming the result is always non-nullish can cause runtime errors if the default is also null or undefined.
Quick: Can you use ?? with && or || without parentheses safely? Commit to yes or no.
Common Belief:Some think ?? can be mixed with && or || without extra parentheses and will work as expected.
Tap to reveal reality
Reality:?? has lower precedence and cannot be mixed with && or || without parentheses; doing so causes syntax errors.
Why it matters:Ignoring this leads to syntax errors and confusion about operator behavior.
Quick: Does enabling strictNullChecks make ?? unnecessary? Commit to yes or no.
Common Belief:Some believe that with strictNullChecks, you don't need ?? because types prevent null or undefined.
Tap to reveal reality
Reality:strictNullChecks enforces null safety but does not provide default values; ?? is still needed to supply defaults at runtime.
Why it matters:Misunderstanding this leads to missing default values and potential runtime errors.
Expert Zone
1
When chaining multiple ?? operators, TypeScript narrows types step-by-step, which can affect complex expressions subtly.
2
Using ?? with non-null assertions (!) can mask nullish values, potentially hiding bugs if misused.
3
The operator cannot be overloaded or customized, so understanding its exact behavior is crucial for advanced type manipulations.
When NOT to use
Avoid ?? when you want to treat all falsy values (like 0, '', false) as missing; in those cases, use ||. Also, do not use ?? in expressions mixing && or || without parentheses due to syntax rules. For complex defaulting logic, consider explicit checks or helper functions.
Production Patterns
In real-world TypeScript projects, ?? is widely used with optional chaining to safely access nested data with defaults. It's common in React props handling, API response parsing, and configuration loading to provide fallback values without overwriting valid falsy data.
Connections
Optional chaining
Builds-on
Optional chaining safely accesses nested properties that might be missing, and combined with ??, it provides safe defaults, making data handling concise and error-free.
Null Object Pattern
Similar pattern
Both nullish coalescing and the Null Object Pattern handle absence by providing safe defaults, reducing the need for null checks and preventing errors.
Fault-tolerant systems (Engineering)
Analogous concept
Just like fault-tolerant systems provide fallback mechanisms only when critical failures occur, nullish coalescing provides defaults only when values are truly missing, improving system robustness.
Common Pitfalls
#1Using || instead of ?? causes valid falsy values to be replaced.
Wrong approach:const count = 0 || 10; // count becomes 10, but 0 is valid
Correct approach:const count = 0 ?? 10; // count remains 0, preserving valid value
Root cause:Confusing falsy values with nullish values leads to incorrect defaulting.
#2Mixing ?? with && or || without parentheses causes syntax errors.
Wrong approach:const result = value && other ?? defaultValue; // Syntax error
Correct approach:const result = (value && other) ?? defaultValue; // Correct usage
Root cause:Operator precedence rules require parentheses to clarify evaluation order.
#3Assuming ?? always returns a non-nullish type regardless of right side.
Wrong approach:const val = null ?? undefined; // val is undefined, still nullish
Correct approach:const val = null ?? 'default'; // val is 'default', non-nullish
Root cause:Not realizing the right side can also be null or undefined.
Key Takeaways
Nullish coalescing (??) returns the right value only if the left is null or undefined, preserving valid falsy values like 0 or ''.
It improves code safety and clarity by distinguishing missing values from valid ones, especially in typed languages like TypeScript.
Combining ?? with optional chaining allows safe access to nested data with proper defaults, reducing runtime errors.
TypeScript's strictNullChecks enhances the power of ?? by enabling precise type narrowing and safer code.
Understanding operator precedence and common pitfalls ensures correct and bug-free use of nullish coalescing.