WalzoneInterview Prep
📞 Interviewing soon? Practice with a realistic AI mock phone interview — it calls you, then scores you. First 15 min FREE →

TypeScript · Expert · question 74 of 100

Can you explain how to use mapped types with conditional types in TypeScript?

📕 Buy this interview preparation book: 100 TypeScript questions & answers — PDF + EPUB for $5

Mapped types and conditional types are powerful features in TypeScript that allow us to create new, complex types based on existing ones. Let’s briefly define each concept before diving into examples on how to use them together.

**Mapped Types** allow us to create new types by transforming the properties of an existing type. They use a ‘for...in‘ clause to iterate through each property in the original type.

**Conditional types** are a way to express type relationships that depend on the relationship between types themselves. They allow you to create types based on conditions, using the syntax ‘T extends U ? X : Y‘.

Now, let’s see an example of how to use mapped types with conditional types:

type MappedConditional<T> = {
    [K in keyof T]: T[K] extends (infer U)[] ? U : T[K]; 
};

The ‘MappedConditional‘ type takes an object type ‘T‘ as its generic parameter, iterates through each property, and checks if the property’s value (‘T[K]‘) is an array. If so, it maps the array element’s type (‘U‘) as the output type, else it maps the original type ‘T[K]‘.

Consider the following example:

type ExampleType = {
    anArray: number[];
    stringWithValue: string;
    nestedArray: string[][];
};

type TransformedExampleType = MappedConditional<ExampleType>;

‘TransformedExampleType‘ would be equivalent to the following type:

type TransformedExampleType = {
    anArray: number;
    stringWithValue: string;
    nestedArray: string[];
};

Here’s another example to understand better how conditional types work within the mapped type:

type ExtractedReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

type MappedReturnTypes<T> = {
    [K in keyof T]: ExtractedReturnType<T[K]>;
};

function foo(): number {
    return 42;
}

function bar(): string {
    return 'hello';
}

type FunctionsType = {
    fooFunction: typeof foo;
    barFunction: typeof bar;
};

type ReturnTypes = MappedReturnTypes<FunctionsType>;

In this example, we first create a utility type ‘ExtractedReturnType‘. This type takes ‘T‘ as its generic parameter, checks if ‘T‘ is a function, and gets the return type of the function (‘R‘) using the ‘infer‘ keyword. If ‘T‘ is not a function, it resolves to ‘never‘.

Then, we create the mapped type ‘MappedReturnTypes‘ that goes over each property in the generic ‘T‘ and maps them to their respective return types using the ‘ExtractedReturnType‘ utility type.

In our example, ‘MappedReturnTypes<FunctionsType>‘ creates a new type ‘ReturnTypes‘ that contains the return types of the function properties:

type ReturnTypes = {
    fooFunction: number;
    barFunction: string;
};

In summary, using mapped types with conditional types in TypeScript enables you to create new, complex types based on the properties and structure of existing types. These powerful features help ensure type safety and code maintainability when working with a variety of data structures and functions.

Reading is step one. Saying it out loud is the interview. Our AI interviewer calls your phone and runs a realistic TypeScript interview — then scores it.
📞 Practice TypeScript — free 15 min
📕 Buy this interview preparation book: 100 TypeScript questions & answers — PDF + EPUB for $5

All 100 TypeScript questions · All topics