Bird
Raised Fist0
Typescriptprogramming~10 mins

Non-distributive conditional types in Typescript - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Non-distributive conditional types
Start with type T
↓
Check if T extends U?
↓
Return X
↓
Wrap with [T
↓
Result
This flow shows how wrapping a type in a tuple [T] prevents conditional types from distributing over unions.
Execution Sample
Typescript
type NonDist<T> = [T] extends [string] ? true : false;
type A = NonDist<string | number>;
// A is false, not true | false
This code checks if a type T is string without distributing over union types.
Execution Table
StepType TCondition [T] extends [string]?Branch TakenResult
1string | numberIs [string | number] assignable to [string]?Nofalse
Exitstring | numberCondition false, no distributionReturn falsefalse
💡 The condition fails because [string | number] is not assignable to [string], so the result is false without distribution.
Variable Tracker
VariableStartAfter Step 1Final
Tstring | numberstring | numberstring | number
Condition ResultN/Afalsefalse
ResultN/Afalsefalse
Key Moments - 2 Insights
Why doesn't the conditional type distribute over the union string | number?
Because T is wrapped in a tuple [T], TypeScript treats it as a single type, preventing distribution. See execution_table step 1 where condition checks [string | number] as a whole.
What would happen if we removed the tuple wrapping [T]?
The conditional type would distribute over each union member separately, resulting in true | false instead of a single false. This is shown by contrasting with the non-wrapped case.
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table at step 1, what is the condition being checked?
AIs string assignable to string?
BIs string assignable to number?
CIs [string | number] assignable to [string]?
DIs number assignable to string?
💡 Hint
Check the 'Condition [T] extends [string]?' column at step 1 in execution_table.
At which step does the conditional type decide the result without distribution?
AStep 1
BStep 2
CExit step
DNo step, it distributes
💡 Hint
Look at the 'Branch Taken' and 'Result' columns in execution_table at step 1.
If we remove the tuple wrapping [T], what would the result type be for string | number?
Atrue
Btrue | false
Cfalse
Dnever
💡 Hint
Recall that without wrapping, conditional types distribute over unions producing a union of results.
Concept Snapshot
Non-distributive conditional types:
Use [T] extends [U] to prevent distribution over unions.
Without wrapping, conditional types distribute over each union member.
Example: type ND<T> = [T] extends [string] ? true : false;
ND<string | number> is false, not true | false.
This helps control type behavior precisely.
Full Transcript
This lesson shows how conditional types in TypeScript normally distribute over union types, but wrapping the type parameter in a tuple prevents this. The example type NonDist<T> uses [T] extends [string] to check if T is string without splitting unions. When T is string | number, the condition fails as a whole, returning false instead of true | false. This is because the tuple wrapping disables distribution. Key points include understanding how wrapping affects conditional checks and how it changes the resulting type. The execution table traces the condition check and result. The quiz tests understanding of the condition, step of decision, and effect of removing the tuple wrapping.

Practice

(1/5)
1. What does a non-distributive conditional type in TypeScript do differently compared to a distributive conditional type?
easy
A. It converts all types to string before evaluation.
B. It always distributes the condition over each member of the union type.
C. It only works with primitive types, not unions.
D. It evaluates the condition on the entire union type as a whole, not on each member separately.

Solution

  1. Step 1: Understand distributive conditional types

    Distributive conditional types apply the condition to each member of a union type separately.
  2. Step 2: Understand non-distributive conditional types

    Non-distributive conditional types evaluate the condition on the entire union type as a single entity, not distributing over members.
  3. Final Answer:

    It evaluates the condition on the entire union type as a whole, not on each member separately. -> Option D
  4. Quick Check:

    Non-distributive = whole union check [OK]
Hint: Non-distributive means no splitting union, check whole type [OK]
Common Mistakes:
  • Thinking conditional always distributes over unions
  • Confusing non-distributive with type narrowing
  • Assuming it only works on primitives
2. Which syntax correctly defines a non-distributive conditional type in TypeScript?
easy
A. type NonDist<T> = T | string ? true : false;
B. type NonDist<T> = T extends string ? true : false;
C. type NonDist<T> = [T] extends [string] ? true : false;
D. type NonDist<T> = T & string ? true : false;

Solution

  1. Step 1: Recognize non-distributive syntax

    Wrapping the type parameter in a tuple, like [T], prevents distribution over unions.
  2. Step 2: Compare options

    type NonDist<T> = [T] extends [string] ? true : false; uses [T] extends [string], which is the correct non-distributive syntax. type NonDist<T> = T extends string ? true : false; distributes over unions. Options C and D are invalid conditional syntax.
  3. Final Answer:

    type NonDist<T> = [T] extends [string] ? true : false; -> Option C
  4. Quick Check:

    Tuple wrapping disables distribution [OK]
Hint: Wrap type in tuple [T] to prevent distribution [OK]
Common Mistakes:
  • Not wrapping type in tuple, causing distribution
  • Using invalid conditional syntax
  • Confusing union with intersection in condition
3. Given the code:
type Test<T> = T extends string ? 'yes' : 'no';
type Result = Test<'a' | number>;

What is the type of Result?
medium
A. 'yes' | 'no'
B. 'yes'
C. 'no'
D. Error

Solution

  1. Step 1: Understand distributive conditional types

    Since T is a union 'a' | number, the condition distributes over each member.
  2. Step 2: Evaluate each member

    'a' extends string is true, so 'yes'; number extends string is false, so 'no'. Combined result is 'yes' | 'no'.
  3. Final Answer:

    'yes' | 'no' -> Option A
  4. Quick Check:

    Distributes over union = 'yes' | 'no' [OK]
Hint: Conditional distributes over union unless wrapped [OK]
Common Mistakes:
  • Assuming whole union checked at once
  • Expecting only 'yes' or only 'no'
  • Confusing union with intersection
4. Identify the error in this non-distributive conditional type:
type NonDist<T> = T extends [string] ? true : false;
medium
A. It incorrectly checks if T extends a tuple containing string, not preventing distribution.
B. It correctly prevents distribution by wrapping T in a tuple.
C. It causes a syntax error because of missing brackets.
D. It always returns false regardless of T.

Solution

  1. Step 1: Analyze the condition

    The condition checks if T extends [string], a tuple type, not wrapping T.
  2. Step 2: Understand distribution prevention

    To prevent distribution, T itself must be wrapped in a tuple: [T] extends [string]. This code does not do that, so distribution is not prevented.
  3. Final Answer:

    It incorrectly checks if T extends a tuple containing string, not preventing distribution. -> Option A
  4. Quick Check:

    Wrap T, not string, to prevent distribution [OK]
Hint: Wrap T in tuple, not the type to check [OK]
Common Mistakes:
  • Wrapping the wrong side of extends
  • Confusing tuple with type wrapper
  • Assuming syntax error instead of logic error
5. How can you write a non-distributive conditional type that checks if a union type T is exactly string | number (no more, no less)?
hard
A. type Exact<T> = T extends string | number ? true : false;
B. type Exact<T> = [T] extends [string | number] ? ([string | number] extends [T] ? true : false) : false;
C. type Exact<T> = T extends [string | number] ? true : false;
D. type Exact<T> = [T] extends [string] | [number] ? true : false;

Solution

  1. Step 1: Prevent distribution with tuple wrapping

    Wrapping T in a tuple [T] prevents distribution over unions.
  2. Step 2: Use mutual assignability checks

    Check [T] extends [string | number] and [string | number] extends [T] to ensure exact match, no extra or missing types.
  3. Final Answer:

    type Exact<T> = [T] extends [string | number] ? ([string | number] extends [T] ? true : false) : false; -> Option B
  4. Quick Check:

    Tuple wrap + mutual extends = exact type check [OK]
Hint: Wrap T and check both extends directions for exact match [OK]
Common Mistakes:
  • Not preventing distribution, causing partial matches
  • Checking only one extends direction
  • Using incorrect tuple wrapping
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard