Using extends and Type Logic - Textnotes

Using extends and Type Logic


Learn how to use conditional types in TypeScript to create dynamic type logic. This module explains the extends keyword, conditional type expressions, and practical real-world examples.

1. Using extends in Conditional Types

Conditional types allow you to define types that depend on a condition. The extends keyword is used to express the condition.

Basic Example


type IsString<T> = T extends string ? "Yes" : "No";

type Test1 = IsString<string>; // "Yes"
type Test2 = IsString<number>; // "No"

This creates a type that evaluates differently based on whether T extends string.

2. Conditional Logic in Types

Conditional types can be combined with generics to create flexible and reusable type logic.

Example: Extracting Type


type ElementType<T> = T extends (infer U)[] ? U : T;

type NumberArray = number[];
type NumberType = ElementType<NumberArray>; // number

type StringType = ElementType<string>; // string

The infer keyword allows extracting a type from a structure dynamically.

Example: Exclude and Extract


type T1 = string | number | boolean;
type OnlyString = Extract<T1, string>; // string
type NotString = Exclude<T1, string>; // number | boolean

Built-in TypeScript utility types like Extract and Exclude are based on conditional types.

3. Practical Examples

Example: Nullable Types


type NonNullable<T> = T extends null | undefined ? never : T;

type Name = NonNullable<string | null | undefined>; // string

Example: Function Return Type


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

function getUser() {
return { id: 1, name: "Muni" };
}

type UserType = ReturnType<typeof getUser>; // { id: number; name: string; }

Conditional types are highly useful for creating advanced type utilities and improving type inference in complex applications.

Conclusion

Conditional types in TypeScript provide powerful tools for creating dynamic, type-safe logic. By using extends, infer, and conditional expressions, developers can design flexible types that adapt to various scenarios, enabling more robust and maintainable code.