TypeScript Advanced Type Manipulation Tricks

TypeScript has become a cornerstone in modern JavaScript development, providing static typing to enhance code reliability and maintainability. While basic types like number, string, and boolean are well - known, TypeScript also offers powerful advanced type manipulation features. These features allow developers to create more flexible, reusable, and type - safe code. In this blog, we will explore the fundamental concepts, usage methods, common practices, and best practices of TypeScript advanced type manipulation tricks.

Table of Contents

  1. Fundamental Concepts
    • Mapped Types
    • Conditional Types
    • Template Literal Types
  2. Usage Methods
    • Using Mapped Types for Property Transformation
    • Leveraging Conditional Types for Conditional Logic in Types
    • Employing Template Literal Types for String Manipulation
  3. Common Practices
    • Creating Read - only Variants of Types
    • Filtering Properties Based on Type
    • Generating Union Types from Arrays
  4. Best Practices
    • Keep Type Manipulation Simple
    • Document Type Manipulation Clearly
    • Test Type Manipulation
  5. Conclusion
  6. References

Fundamental Concepts

Mapped Types

Mapped types allow you to create new types by transforming each property in an existing type. They are similar to map function in JavaScript arrays, but for types.

// Example of a simple mapped type
type ReadonlyType<T> = {
    readonly [P in keyof T]: T[P];
};

interface User {
    name: string;
    age: number;
}

type ReadonlyUser = ReadonlyType<User>;

Conditional Types

Conditional types allow you to choose one type based on a condition. They have a syntax similar to the ternary operator in JavaScript.

// Example of a conditional type
type IsString<T> = T extends string? true : false;

type Result1 = IsString<string>; // true
type Result2 = IsString<number>; // false

Template Literal Types

Template literal types allow you to create new string types by interpolating other types. They are similar to template literals in JavaScript.

// Example of a template literal type
type Prefix<T> = `prefix-${T}`;

type NewType = Prefix<'value'>; // "prefix-value"

Usage Methods

Using Mapped Types for Property Transformation

Mapped types can be used to transform properties of an existing type. For example, making all properties optional.

type OptionalType<T> = {
    [P in keyof T]?: T[P];
};

interface Book {
    title: string;
    author: string;
    year: number;
}

type OptionalBook = OptionalType<Book>;

Leveraging Conditional Types for Conditional Logic in Types

Conditional types can be used to implement conditional logic in types. For example, filtering out properties of a certain type.

type FilterProperties<T, U> = {
    [P in keyof T as T[P] extends U? P : never]: T[P];
};

interface Example {
    name: string;
    age: number;
    isAdmin: boolean;
}

type StringProperties = FilterProperties<Example, string>; // { name: string }

Employing Template Literal Types for String Manipulation

Template literal types can be used for string manipulation. For example, creating event names based on an action.

type EventName<T extends string> = `${T}Event`;

type ClickEvent = EventName<'click'>; // "clickEvent"

Common Practices

Creating Read - only Variants of Types

As shown earlier, mapped types can be used to create read - only variants of existing types.

type ReadonlyVariant<T> = {
    readonly [P in keyof T]: T[P];
};

interface Config {
    apiKey: string;
    baseUrl: string;
}

type ReadonlyConfig = ReadonlyVariant<Config>;

Filtering Properties Based on Type

Conditional types can be used to filter properties based on their type.

type NumberProperties<T> = {
    [P in keyof T as T[P] extends number? P : never]: T[P];
};

interface Data {
    id: number;
    name: string;
    price: number;
}

type OnlyNumbers = NumberProperties<Data>; // { id: number; price: number }

Generating Union Types from Arrays

You can use the typeof operator along with template literal types to generate union types from arrays.

const colors = ['red', 'green', 'blue'] as const;

type ColorUnion = typeof colors[number]; // "red" | "green" | "blue"

Best Practices

Keep Type Manipulation Simple

Complex type manipulations can make the code hard to understand and maintain. Try to break down complex type operations into smaller, more manageable steps.

Document Type Manipulation Clearly

Since type manipulation can be hard to understand at a glance, it’s important to document the purpose and functionality of type manipulations clearly. Use comments to explain what each part of the type manipulation is doing.

Test Type Manipulation

Just like regular code, type manipulations should be tested. You can use tools like tsd to test types in TypeScript projects.

Conclusion

TypeScript advanced type manipulation tricks offer a powerful set of tools for creating more flexible, reusable, and type - safe code. Mapped types, conditional types, and template literal types are just a few examples of the advanced features that TypeScript provides. By understanding the fundamental concepts, usage methods, common practices, and best practices, developers can leverage these features to write high - quality TypeScript code.

References