Hone logo
Hone
Problems

Mastering Partial Types in TypeScript

This challenge focuses on understanding and implementing utility types in TypeScript, specifically the concept of a "partial" type. A partial type is incredibly useful for scenarios where you need to create a new type where all properties of an existing type are optional. This is common when dealing with form data, configuration objects, or when updating existing data structures where not all fields might be provided.

Problem Description

Your task is to create a TypeScript utility type named PartialType<T> that takes a generic type T and returns a new type. In this new type, every property that exists in T should be made optional.

Key Requirements:

  • The PartialType<T> utility type must correctly transform a given type T.
  • All properties of T should become optional in the resulting type.
  • If a property in T was already optional, it should remain optional.
  • If a property in T was required, it must become optional.

Expected Behavior:

When PartialType<T> is applied to a type, the resulting type should have the same keys as T, but each key's corresponding value type should be preceded by a ?, indicating it's an optional property.

Edge Cases:

  • Consider how PartialType<T> should behave with an empty object type ({}).
  • Consider how it should behave with types that have already optional properties.

Examples

Example 1:

type User = {
  id: number;
  name: string;
  email?: string;
};

// Apply PartialType
type PartialUser = PartialType<User>;

// Expected type for PartialUser:
// {
//   id?: number;
//   name?: string;
//   email?: string;
// }

const user1: PartialUser = { id: 1 };
const user2: PartialUser = { name: "Alice", email: "alice@example.com" };
const user3: PartialUser = {};

Explanation: The User type has id and name as required properties, and email as an optional property. PartialType<User> makes id and name optional, while email remains optional.

Example 2:

type Settings = {
  theme: "dark" | "light";
  fontSize: number;
};

// Apply PartialType
type PartialSettings = PartialType<Settings>;

// Expected type for PartialSettings:
// {
//   theme?: "dark" | "light";
//   fontSize?: number;
// }

const settings1: PartialSettings = { theme: "dark" };
const settings2: PartialSettings = { fontSize: 16 };

Explanation: Both theme and fontSize are required in Settings. PartialType<Settings> makes both of them optional.

Example 3:

type EmptyConfig = {};

// Apply PartialType
type PartialEmptyConfig = PartialType<EmptyConfig>;

// Expected type for PartialEmptyConfig:
// {}

const emptyConfig: PartialEmptyConfig = {};

Explanation: An empty object type has no properties, so making all of its (non-existent) properties optional results in an empty object type.

Constraints

  • Your solution must be a TypeScript utility type.
  • The utility type must be named PartialType.
  • It must accept a single generic type parameter T.
  • No external libraries or packages are allowed; only standard TypeScript features.
  • The solution should be purely a type-level operation; no runtime code is required.

Notes

This challenge is designed to test your understanding of mapped types and conditional types in TypeScript. Think about how you can iterate over the keys of a given type and transform each of its properties. The built-in Partial<T> utility type in TypeScript's standard library achieves this exact functionality. This exercise is about recreating that functionality from scratch.

Loading editor...
typescript