Hone logo
Hone
Problems

Advanced Mapped Types: Utility Types in TypeScript

Mapped types are a powerful feature in TypeScript that allow you to transform existing types into new ones. This challenge focuses on building several common utility types using mapped types, demonstrating your understanding of conditional types, key remapping, and type transformations. Creating these utility types is crucial for writing reusable and maintainable TypeScript code.

Problem Description

Your task is to implement several utility types using TypeScript's mapped types. These utility types are commonly used in libraries and frameworks to provide flexible and type-safe operations on objects. You will need to define these types using mapped types, conditional types, and potentially other advanced TypeScript features.

Specifically, you need to implement the following utility types:

  1. PartialBy<T, K>: Makes a subset of properties in T optional. K is a type representing the keys to make optional.
  2. ReadonlyBy<T, K>: Makes a subset of properties in T readonly. K is a type representing the keys to make readonly.
  3. PickBy<T, K>: Creates a new type by picking a subset of properties from T. K is a type representing the keys to pick.
  4. OmitBy<T, K>: Creates a new type by omitting a subset of properties from T. K is a type representing the keys to omit.
  5. DeepPartial<T>: Recursively makes all properties of T optional, including properties of nested objects.

Examples

Example 1: PartialBy

Input:
interface Person {
  name: string;
  age: number;
  address: {
    street: string;
    city: string;
  };
}

type PartialPersonAddress = PartialBy<Person, 'address'>;

Output:
type PartialPersonAddress = {
  name: string;
  age: number;
  address?: {
    street: string;
    city: string;
  };
}

Explanation: The 'address' property (and its nested properties) are now optional.

Example 2: ReadonlyBy

Input:
interface Product {
  id: number;
  name: string;
  price: number;
  description?: string;
}

type ReadonlyProductId = ReadonlyBy<Product, 'id'>;

Output:
type ReadonlyProductId = {
  readonly id: number;
  name: string;
  price: number;
  description?: string;
}

Explanation: The 'id' property is now readonly.

Example 3: PickBy

Input:
interface Config {
  apiUrl: string;
  timeout: number;
  debug: boolean;
}

type PickedConfig = PickBy<Config, 'apiUrl' | 'debug'>;

Output:
type PickedConfig = {
  apiUrl: string;
  debug: boolean;
}

Explanation: Only 'apiUrl' and 'debug' properties are included in the new type.

Example 4: OmitBy

Input:
interface User {
  id: number;
  username: string;
  email: string;
}

type UserWithoutId = OmitBy<User, 'id'>;

Output:
type UserWithoutId = {
  username: string;
  email: string;
}

Explanation: The 'id' property is omitted from the new type.

Example 5: DeepPartial

Input:
interface Settings {
  theme: 'light' | 'dark';
  notifications: {
    email: boolean;
    push: boolean;
  };
}

type DeeplyPartialSettings = DeepPartial<Settings>;

Output:
type DeeplyPartialSettings = {
  theme?: 'light' | 'dark';
  notifications?: {
    email?: boolean;
    push?: boolean;
  };
}

Explanation: All properties, including nested ones, are made optional.

Constraints

  • All utility types must be implemented using mapped types and conditional types.
  • The code should be well-formatted and easy to understand.
  • The types should be generic and work with any valid TypeScript type.
  • The DeepPartial type must handle arbitrarily nested objects.
  • No external libraries are allowed.

Notes

  • Consider using keyof to iterate over the keys of a type.
  • Conditional types (T extends U ? X : Y) are essential for implementing these utility types.
  • Think about how to handle nested objects when creating DeepPartial. Recursion might be helpful.
  • Pay close attention to the type signatures and ensure they accurately reflect the intended behavior.
  • Start with PartialBy and ReadonlyBy as they are generally simpler, then move on to PickBy and OmitBy, and finally tackle DeepPartial.
Loading editor...
typescript