JavaScript > TypeScript > Advanced TypeScript > Utility types

Using Partial and Readonly Utility Types in TypeScript

This snippet demonstrates how to use the Partial and Readonly utility types in TypeScript to create more flexible and type-safe interfaces.

Understanding Partial

The Partial utility type constructs a type where all properties of T are set to optional. This is useful when you want to create an object where you only need to specify some of the properties initially, and add the rest later. It essentially transforms every property from prop: Type to prop?: Type.

Code Example for Partial

In this example, PartialProduct allows us to update a product with only a subset of its properties. The updateProduct function can accept an object containing only the properties that need to be updated. The id remains required, since it's passed as a separate argument.

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

type PartialProduct = Partial<Product>;

const updateProduct = (id: number, updates: PartialProduct): void => {
  // Logic to update the product in the database
  console.log(`Updating product ${id} with:`, updates);
};

updateProduct(123, { price: 19.99 }); // Only updating the price
updateProduct(456, { name: 'New Product Name', description: 'A fantastic new product' }); //Updating name and description

Understanding Readonly

The Readonly utility type constructs a type where all properties of T are set to readonly. This means that once the properties are initialized, they cannot be reassigned. This is helpful for creating immutable objects or preventing accidental modification of properties. It transforms every property from prop: Type to readonly prop: Type.

Code Example for Readonly

Here, readonlyConfig is a Readonly version of the Configuration interface. Any attempt to modify its properties will result in a TypeScript compilation error, enforcing immutability. This makes your code more predictable and less prone to bugs.

interface Configuration {
  apiUrl: string;
  timeout: number;
}

const initialConfig: Configuration = {
  apiUrl: 'https://example.com/api',
  timeout: 5000,
};

const readonlyConfig: Readonly<Configuration> = initialConfig;

// readonlyConfig.apiUrl = 'https://newapi.com'; // Error: Cannot assign to 'apiUrl' because it is a read-only property.

console.log(readonlyConfig.apiUrl);

Concepts Behind the Snippet

TypeScript utility types are built-in type transformations that help you manipulate and create new types based on existing ones. Partial and Readonly are just two examples; others include Required, Pick, Omit, and more. They allow you to write more concise and maintainable type definitions.

Real-Life Use Case

Imagine building a complex form where users might only fill in certain fields initially. Partial is perfect for representing the data being submitted in stages. For configuration objects that shouldn't be changed after initialization, Readonly can ensure data integrity.

Best Practices

Use Partial when dealing with optional properties or staged data input. Use Readonly for immutable data structures or configuration objects that should not be modified after initialization. Always strive to define clear interfaces and types before applying utility types.

Interview Tip

Be prepared to explain the differences between Partial and Required, or Readonly and regular properties. Also, be ready to discuss use cases where each would be beneficial.

When to use them

Use Partial when a function accepts an object representing only some of the properties to be updated. Use Readonly when you want to enforce immutability on an object, preventing accidental modification.

Memory footprint

Partial and Readonly themselves don't directly impact memory footprint at runtime, as they are TypeScript constructs used during compile time to enforce type safety. The underlying JavaScript objects will still have the same memory footprint regardless of whether these utility types were used.

Alternatives

Without Partial, you would have to define a separate interface with all optional properties. Without Readonly, you would have to rely on conventions or runtime checks to prevent modification, which is less reliable than compile-time type checking.

Pros

Partial improves code flexibility by allowing partial updates. Readonly enhances data integrity by enforcing immutability. Both improve type safety and reduce potential errors at runtime.

Cons

Overuse of Partial might hide potential issues where properties are expected but not provided. Readonly, while helpful, may require more careful planning when designing mutable data structures.

FAQ

  • What happens if I try to modify a Readonly property at runtime?

    TypeScript will prevent this at compile time, issuing a type error. However, if you bypass TypeScript (e.g., through JavaScript code), the Readonly property will not prevent modification at runtime. TypeScript's type system disappears after compilation.
  • Can I combine Partial and Readonly?

    Yes, you can! For example, Readonly> creates a type where all properties of Product are optional and read-only.