Hone logo
Hone
Problems

Typed Builder Pattern in TypeScript

The Builder pattern is a creational design pattern that allows you to construct complex objects step-by-step. This is particularly useful when an object has many optional parameters or configurations. This challenge asks you to implement a Builder pattern in TypeScript, ensuring strong typing throughout the process to improve code safety and maintainability.

Problem Description

You are tasked with creating a Product class and a ProductBuilder class in TypeScript. The Product class will represent a complex product with several properties, some of which are optional. The ProductBuilder will provide a fluent interface for constructing Product instances, allowing clients to set properties in a controlled and readable manner.

What needs to be achieved:

  • Define a Product class with properties: name (string, required), description (string, optional), price (number, required), category (string, optional), and tags (string[], optional).
  • Create a ProductBuilder class that allows setting each of these properties individually.
  • The ProductBuilder should have methods for setting name, description, price, category, and tags.
  • The ProductBuilder should have a build() method that returns a fully constructed Product instance.
  • Ensure that the name and price properties are required and cannot be left unset during the building process.

Key Requirements:

  • Strong Typing: All properties and methods should be strongly typed to prevent errors.
  • Fluent Interface: The builder methods should return the builder instance itself (this) to allow for method chaining.
  • Immutability (Optional but Recommended): Consider making the Product instance immutable after it's built.
  • Error Handling: The build() method should throw an error if the required properties (name, price) are not set.

Expected Behavior:

A client should be able to use the ProductBuilder to create Product instances with varying configurations. The builder should enforce the required properties and provide a clear and readable way to set optional properties.

Edge Cases to Consider:

  • What happens if the client tries to build a product without setting the required properties?
  • How should the builder handle invalid input (e.g., a non-positive price)? (This is not strictly required, but demonstrates good design.)
  • Consider how to handle the tags property, which is an array of strings.

Examples

Example 1:

Input: Using the builder to create a product with all properties set.
builder.setName("Awesome Widget").setDescription("A truly awesome widget").setPrice(19.99).setCategory("Gadgets").setTags(["widget", "awesome", "new"]);
Output: A Product object with name: "Awesome Widget", description: "A truly awesome widget", price: 19.99, category: "Gadgets", tags: ["widget", "awesome", "new"]
Explanation: The builder sets all properties as specified and returns a fully configured Product.

Example 2:

Input: Using the builder to create a product with only required properties set.
builder.setName("Basic Product").setPrice(9.99);
Output: A Product object with name: "Basic Product", price: 9.99, description: undefined, category: undefined, tags: undefined
Explanation: Only the required properties are set; optional properties remain undefined.

Example 3: (Edge Case)

Input: Attempting to build a product without setting the name.
builder.setPrice(25.00).build();
Output: Error: "Name is required."
Explanation: The build method throws an error because the required 'name' property was not set.

Constraints

  • The name property must be a string.
  • The description property must be a string or undefined.
  • The price property must be a number greater than 0.
  • The category property must be a string or undefined.
  • The tags property must be an array of strings or undefined.
  • The build() method must throw an error if name or price are not set.
  • The solution must be written in TypeScript.

Notes

  • Consider using TypeScript's optional properties and union types to define the properties of the Product class.
  • The fluent interface is a key aspect of the Builder pattern. Make sure your builder methods return this to enable method chaining.
  • Think about how to handle potential errors, such as invalid input values. While not strictly required, it demonstrates good design principles.
  • Focus on creating a clean, readable, and well-typed solution.
Loading editor...
typescript