📖 Scenario: Imagine you are building a TypeScript utility to check if a type is exactly string or not, without distributing over unions. This helps when you want to treat unions as a whole instead of their parts.
🎯 Goal: You will create a non-distributive conditional type called IsExactlyString that returns true if the type is exactly string, and false otherwise. Then you will test it with different types.
📋 What You'll Learn
Create a generic type called IsExactlyString that takes a type parameter T.
Use a tuple wrapper to prevent distribution in the conditional type.
Return true if T is exactly string, else false.
Create variables with types using IsExactlyString for string, number, and string | number.
Print the types of these variables to verify the results.
💡 Why This Matters
🌍 Real World
Non-distributive conditional types help when you want to check or transform types exactly without breaking unions into parts. This is useful in libraries and frameworks that rely on precise type behavior.
💼 Career
Understanding advanced TypeScript types like non-distributive conditional types is valuable for frontend and backend developers working with complex type-safe codebases, improving code quality and reducing bugs.
Progress0 / 4 steps
1
Create the generic type IsExactlyString
Create a generic type called IsExactlyString with a type parameter T. Use a conditional type that compares [T] to [string] to avoid distribution. Return true if they are equal, otherwise false.
Typescript
Hint
Wrap the type parameter T and string in tuples to prevent distribution.
2
Create variables to test IsExactlyString
Create three variables: testString with type IsExactlyString, testNumber with type IsExactlyString, and testUnion with type IsExactlyString.
Typescript
Hint
Use the generic type IsExactlyString with the exact types string, number, and string | number.
3
Assign values to variables to check type compatibility
Assign true to testString, and false to both testNumber and testUnion.
Typescript
Hint
Assign the boolean values true or false matching the expected results of the type checks.
4
Print the results to verify the non-distributive conditional type
Use console.log to print the values of testString, testNumber, and testUnion.
Typescript
Hint
Print each variable on its own line using console.log.
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
Step 1: Understand distributive conditional types
Distributive conditional types apply the condition to each member of a union type separately.
Non-distributive conditional types evaluate the condition on the entire union type as a single entity, not distributing over members.
Final Answer:
It evaluates the condition on the entire union type as a whole, not on each member separately. -> Option D
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
Step 1: Recognize non-distributive syntax
Wrapping the type parameter in a tuple, like [T], prevents distribution over unions.
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.
Final Answer:
type NonDist<T> = [T] extends [string] ? true : false; -> Option C
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
Step 1: Understand distributive conditional types
Since T is a union 'a' | number, the condition distributes over each member.
Step 2: Evaluate each member
'a' extends string is true, so 'yes'; number extends string is false, so 'no'. Combined result is 'yes' | 'no'.
Final Answer:
'yes' | 'no' -> Option A
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
Step 1: Analyze the condition
The condition checks if T extends [string], a tuple type, not wrapping T.
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.
Final Answer:
It incorrectly checks if T extends a tuple containing string, not preventing distribution. -> Option A
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;