Using Conditional Types for Overload Replacement in TypeScript
📖 Scenario: Imagine you are building a simple calculator function that can add numbers or concatenate strings. Instead of writing multiple overloads, you want to use TypeScript's conditional types to decide the return type based on the input type.
🎯 Goal: Create a function called combine that takes either two numbers or two strings. Use conditional types to make the return type number when inputs are numbers, and string when inputs are strings. Then test the function with both types.
📋 What You'll Learn
Create a generic type CombineResult<T> that uses conditional types to return number if T is number, otherwise string.
Write a function combine with two parameters a and b of the same generic type T.
Use the CombineResult<T> type as the return type of combine.
Inside combine, add numbers or concatenate strings based on the type of a.
Test combine with two numbers and two strings and print the results.
💡 Why This Matters
🌍 Real World
Conditional types help create flexible functions that adapt their return types based on input types, reducing the need for multiple overloads and making code easier to maintain.
💼 Career
Understanding conditional types is important for TypeScript developers to write clean, type-safe code that works well in large projects and libraries.
Progress0 / 4 steps
1
Create the generic conditional type
Create a generic type called CombineResult<T> that returns number if T is number, otherwise returns string.
Typescript
Hint
Use T extends number ? number : string to create the conditional type.
2
Write the combine function signature
Write a generic function called combine with two parameters a and b of type T. Use CombineResult<T> as the return type.
Typescript
Hint
Use function combine<T>(a: T, b: T): CombineResult<T> for the signature.
3
Implement the combine function logic
Inside the combine function, check if a is a number using typeof a === 'number'. If yes, return the sum of a and b. Otherwise, return the concatenation of a and b as strings.
Typescript
Hint
Use typeof to check the type and cast the return value to CombineResult<T>.
4
Test the combine function and print results
Call combine with numbers 5 and 10 and store in resultNumber. Call combine with strings 'Hello' and 'World' and store in resultString. Print both results using console.log.
Typescript
Hint
Use console.log(resultNumber) and console.log(resultString) to print the results.
Practice
(1/5)
1. What is the main purpose of using conditional types in TypeScript for overload replacement?
easy
A. To enforce runtime type checking in JavaScript
B. To create multiple functions with the same name but different parameters
C. To select a type based on a condition, replacing multiple overloads with one type
D. To convert all types to strings automatically
Solution
Step 1: Understand conditional types
Conditional types allow choosing a type based on a condition, like an if-else for types.
Step 2: Relate to overload replacement
They replace multiple function overloads by selecting the correct return type based on input types.
Final Answer:
To select a type based on a condition, replacing multiple overloads with one type -> Option C
Quick Check:
Conditional types = overload replacement [OK]
Hint: Think 'if-else' but for types to replace overloads [OK]
Believing conditional types convert types to strings
2. Which of the following is the correct syntax for a conditional type in TypeScript?
easy
A. type Result = if (T extends U) { X } else { Y };
B. type Result = T == U ? X : Y;
C. type Result = T ? U : V;
D. type Result = T extends U ? X : Y;
Solution
Step 1: Recall conditional type syntax
Conditional types use the syntax: type Result = T extends U ? X : Y;
Step 2: Compare options
type Result = T extends U ? X : Y; matches the correct syntax. Options A, C, and D use invalid or incorrect syntax.
Final Answer:
type Result = T extends U ? X : Y; -> Option D
Quick Check:
Conditional type syntax = type Result = T extends U ? X : Y; [OK]
Hint: Remember: 'extends' with '?' and ':' for conditional types [OK]
Common Mistakes:
Using if-else syntax inside type definitions
Confusing ternary operator with conditional types
Using '==' instead of 'extends' keyword
3. Given the code below, what is the type of result?
type IsString<T> = T extends string ? "Yes" : "No";
let result: IsString<number>;
medium
A. "Yes"
B. "No"
C. number
D. string
Solution
Step 1: Analyze the conditional type
The type IsString<T> returns "Yes" if T extends string, else "No".
Step 2: Apply to number
Since number does not extend string, the type is "No".
Final Answer:
"No" -> Option B
Quick Check:
number extends string? No [OK]
Hint: Check if type extends string; if not, result is "No" [OK]
Common Mistakes:
Assuming number extends string
Confusing type with value
Ignoring the conditional type logic
4. Identify the error in this conditional type usage:
type Check<T> = T extends number ? "Num" : "NotNum";
function test<T>(value: T): Check<T> {
if (typeof value === "number") {
return "Num";
} else {
return "NotNum";
}
}
medium
A. Function return type does not match because conditional types are not resolved at runtime
B. The conditional type syntax is incorrect
C. The function parameter should be typed as number
D. The if condition should check for string instead of number
Solution
Step 1: Understand conditional types vs runtime
Conditional types exist only at compile time and cannot be used to enforce runtime return types directly.
Step 2: Check function return
The function tries to return a value matching Check<T>, but TypeScript cannot guarantee this at runtime, causing a type error.
Final Answer:
Function return type does not match because conditional types are not resolved at runtime -> Option A
Quick Check:
Conditional types = compile-time only [OK]
Hint: Remember conditional types are compile-time, not runtime checks [OK]
Common Mistakes:
Thinking conditional types work at runtime
Misusing conditional type syntax
Changing parameter type unnecessarily
5. How can conditional types replace multiple overloads in this example?
function format(value: string): string;
function format(value: number): string;
function format(value: any): string {
return value.toString();
}
Choose the best conditional type signature to replace these overloads.
hard
A. function format<T>(value: T): T extends string | number ? string : never;
B. function format<T>(value: T): string;
C. function format(value: T): T extends string ? string : string;
D. function format<T>(value: T): T extends string ? string : number;
Solution
Step 1: Understand original overloads
Both string and number inputs return a string output.
Step 2: Choose conditional type matching overloads
function format<T>(value: T): T extends string | number ? string : never; restricts T to string or number and returns string for those, else never (disallowed).
Step 3: Check other options
function format<T extends string | number>(value: T): T extends string ? string : string;'s return type is redundant; function format<T>(value: T): string; allows any type; function format<T>(value: T): T extends string ? string : number; returns number incorrectly.
Final Answer:
function format<T>(value: T): T extends string | number ? string : never; -> Option A
Quick Check:
Conditional type restricts inputs and return string [OK]
Hint: Use conditional type to restrict inputs and unify return type [OK]
Common Mistakes:
Allowing any input type without restriction
Returning wrong types for some inputs
Ignoring the need to exclude unsupported types
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.