TypeScript has become an indispensable tool for modern developers, offering powerful features to ensure robust and maintainable codebases. Among its most advanced capabilities are Conditional Types and Mapped Types, which provide granular control over type transformations and decisions. These features unlock incredible flexibility and precision, making TypeScript much more than just “JavaScript with types.”
In this blog, we’ll dive into these advanced types, explore their syntax and use cases, and uncover how they can elevate your TypeScript projects.
Conditional types allow you to express type relationships and logic that depend on conditions. They’re akin to JavaScript’s ternary operator but tailored for types.
T extends U ? X : Y
This reads as: If T extends U, then the type is X; otherwise, it’s Y.
Use Case: Simplified Type Inference
Imagine you want to create a utility type that extracts the return type of a function. Using conditional types, you can achieve this easily:
type ReturnType<T> = T extends (…args: any[]) => infer R ? R : never;
const exampleFn = (x: number): string => x.toString(); type ExampleReturnType = ReturnType<typeof exampleFn>; // string
Here, the infer keyword is used to capture and extract the return type.

Use Case: Excluding Types
Conditional types also shine in type filtering. For example, you can create a type that excludes certain types:
type Exclude<T, U> = T extends U ? never : T;
type AllowedTypes = Exclude<string | number | boolean, boolean>; // string | number
Mapped types allow you to transform the properties of a given type systematically. They are incredibly useful for creating variations of existing types without manual repetition.
type MappedType<T> = { [P in keyof T]: Transformation };
Here, P iterates over the keys of T, and you can apply any transformation to the property types.
Use Case: Making Properties Optional
Suppose you have a type where you want to make all properties optional:
type Partial<T> = { [P in keyof T]?: T[P]; };
type User = { name: string; age: number; };
type OptionalUser = Partial<User>; // { name?: string; age?: number }

Use Case: Read-Only Properties
You can make all properties read-only using mapped types:
type Readonly<T> = { readonly [P in keyof T]: T[P]; };
type ReadonlyUser = Readonly<User>;
The true power of these types emerges when combined. For instance, you can create a utility type that makes properties read-only only if they match a certain condition:
type ReadonlyIfString<T> = { [P in keyof T]: T[P] extends string ? Readonly<T[P]> : T[P]; };
type MixedType = { name: string; age: number; };
type ConditionalReadonly = ReadonlyIfString<MixedType>;
Understanding and leveraging Conditional and Mapped Types will elevate your TypeScript skills to the next level. These advanced types not only improve type safety but also help create more expressive, reusable, and maintainable code. Whether you’re dealing with API responses, form validation, or type filtering, these tools provide the flexibility to build smarter type systems.
TypeScript continues to push the boundaries of static typing in JavaScript, and mastering these features is a step toward unlocking its full potential. Happy coding!
Hey, having any query? Our experts are just one click away to respond you.
Contact Us