Ts Conditional Types
Conditional Types is one of the most powerful features in the TypeScript type system.
It allows dynamically selecting types based on conditions, similar to ternary expressions in programming languages.
Conditional Types make type definitions more flexible and are the foundation for implementing advanced utility types.
* * *
* * *
## Why Conditional Types Are Needed
In actual TypeScript development, we often need to return different types based on different input types.
For example, a function might accept string or number parameters, and we need to return different result types based on the parameter type.
Conditional Types provide the ability to perform logical judgments at the type level, making type definitions more flexible and powerful.
> **Concept Explanation:** The syntax for Conditional Types is `T extends U ? X : Y`. If type T can be assigned to type U, then return type X, otherwise return type Y.
* * *
## Basic Syntax
Conditional Types use ternary expression syntax to perform conditional checks at the type level.
This allows us to dynamically compute return types based on input types.
## Example
// Conditional Type syntax: T extends U ? X : Y
// If T is string type, return true, otherwise return false
type IsString= T extends string ?true:false;
// Using Conditional Types
// string extends string is true, so type A is true
type A = IsString;
// number extends string is false, so type B is false
type B = IsString;
// Using these types
var a: A =true;
var b: B =false;
console.log("string is string?: "+ a);
console.log("number is string?: "+ b);
**Result:**
string is string?: true number is string?: false
> **Explanation:** Conditional Types are automatically evaluated during type checking to generate concrete types.
* * *
## Practical Application: Type Filtering
One of the most common applications of Conditional Types is filtering types.
For example, you can create a type to exclude null and undefined.
## Example
// Using Conditional Types to implement NonNullable
// If T is null or undefined, return never (empty type), otherwise return T itself
type NonNullable= T extends null|undefined? never : T;
// Using NonNullable type
// string is not null/undefined, so type is string
type A = NonNullable;
// null is null/undefined, so type is never
type B = NonNullable;
// undefined is null/undefined, so type is never
type C = NonNullable;
// Verifying types
var a: A ="hello";
console.log("Non-null: "+ a);
**Result:**
Non-null: hello
> **never Type:** never represents a type that never exists. When conditions are not met, TypeScript uses never to represent an "unavailable" type.
* * *
## Type Inference: infer Keyword
The infer keyword is one of the most powerful features in Conditional Types.
It allows "extracting" or "inferring" specific type parts from a type.
## Example
// Using infer to infer function return type
// If T is a function type, return the inferred return type R, otherwise return never
type ReturnType= T extends(...args: any[])=> infer R ? R : never;
// Define a function that returns a user object
function getUser(){
return{ name:"Alice"};
}
// Define a function that returns a number
function getNumber(){
return 42;
}
// Using ReturnType to get function return types
// Inferred as { name: string }
type R1 = ReturnType;
// Inferred as number
type R2 = ReturnType;
// Using inferred types
var r1: R1 ={ name:"Bob"};
var r2: R2 =100;
console.log("User: "+ JSON.stringify(r1));
console.log("Number: "+ r2);
**Result:**
User: {"name":"Bob"}Number: 100
> **Role of infer:** infer is like a "variable" in the type system that can capture specific parts of a type and use them in the result type.
* * *
## Distributive Conditional Types
When the generic parameter of a Conditional Type is a union type, it automatically performs "distribution" processing.
In other words, the condition is executed separately for each member of the union type, and then the results are merged.
## Example
// ToArray converts type T to an array type
// When T is a union type, it automatically distributes processing for each type
type ToArray= T extends any ? T[]: never;
// Union types are automatically distributed
// string | number is distributed as: ToArray | ToArray
// Which is: string[] | number[]
type StrOrNum = ToArray;
// Can assign string[] or number[]
var arr: StrOrNum =;
// Can also assign number
arr =42;
console.log("Array: "+ arr);
**Result:**
Array: 42
> **Distribution Mechanism:** The distribution feature of Conditional Types is automatically enabled. To disable distribution, you can use square brackets: ` extends U`.
* * *
## Combining Conditional Types with Mapped Types
Conditional Types can be combined with Mapped Types to create powerful type transformation tools.
This combination is the foundation for implementing TypeScript's built-in utility types.
## Example
// Define User interface
interface User {
// User ID
id: number;
// Username
name: string;
// User email
email: string;
}
// Using Mapped Types and Conditional Types to implement Partial
// Iterate over all properties of T, add optional modifier ?
type Partial={
?: T;
};
// Using Mapped Types and Conditional Types to implement Required
// Iterate over all properties of T, remove optional modifier -?
type Required={
-?: T;
};
// Using Partial: all properties become optional
var partial: Partial={ name:"Alice"};
// Using Required: make properties of Partial required
// Need to have Partial type first
type RequiredUser = Required<Partial>;
var required: RequiredUser ={ name:"Bob", id:1};
console.log("Optional: "+ JSON.stringify(partial));
console.log("
YouTip