Hone logo
Hone
Problems

Mastering Discriminated Unions in TypeScript

Discriminated unions are a powerful pattern in TypeScript for modeling states or different types of data within a single structure. They allow you to represent a value that could be one of several distinct possibilities, and safely narrow down its type based on a common "discriminant" property. This challenge will help you practice creating and working with these unions to build more robust and type-safe applications.

Problem Description

Your task is to implement a system that represents different types of geometric shapes using discriminated unions in TypeScript. You will define a union type that can represent circles, rectangles, and triangles, each with its own specific properties. You will then create a function that accepts any of these shapes and calculates its area, demonstrating type safety and pattern matching with discriminated unions.

Key Requirements:

  1. Define a Shape discriminated union type: This union should include types for Circle, Rectangle, and Triangle.
  2. Each shape type must have a unique literal type discriminant: This will typically be a type property (e.g., "circle", "rectangle", "triangle").
  3. Define specific properties for each shape:
    • Circle: Requires a radius.
    • Rectangle: Requires width and height.
    • Triangle: Requires base and height.
  4. Implement an calculateArea function: This function should take a Shape as input and return its calculated area as a number.
  5. Utilize type narrowing: Inside calculateArea, use control flow (like if statements or a switch statement) to determine the specific shape type and apply the correct area calculation formula.

Expected Behavior:

The calculateArea function should correctly calculate the area for each shape type based on its properties. For example:

  • Circle area: π * radius^2
  • Rectangle area: width * height
  • Triangle area: 0.5 * base * height

Edge Cases to Consider:

  • While not explicitly required for this challenge, in a real-world scenario, you might consider how to handle invalid input (e.g., negative dimensions). For this challenge, assume valid positive numerical inputs.

Examples

Example 1:

// Input Shape
const myCircle: Shape = {
  type: "circle",
  radius: 5
};

// Expected Output
// calculateArea(myCircle) should return approximately 78.5398... (π * 5^2)

Explanation: The input is a circle with a radius of 5. The function should identify it as a circle and apply the circle area formula.

Example 2:

// Input Shape
const myRectangle: Shape = {
  type: "rectangle",
  width: 10,
  height: 4
};

// Expected Output
// calculateArea(myRectangle) should return 40 (10 * 4)

Explanation: The input is a rectangle with width 10 and height 4. The function should identify it as a rectangle and apply the rectangle area formula.

Example 3:

// Input Shape
const myTriangle: Shape = {
  type: "triangle",
  base: 6,
  height: 8
};

// Expected Output
// calculateArea(myTriangle) should return 24 (0.5 * 6 * 8)

Explanation: The input is a triangle with base 6 and height 8. The function should identify it as a triangle and apply the triangle area formula.

Constraints

  • All input dimensions (radius, width, height, base) will be positive number types.
  • The type property for each shape will always be one of the defined literal strings: "circle", "rectangle", or "triangle".
  • The calculateArea function should return a number.

Notes

  • Remember to import Math.PI for the circle area calculation.
  • A switch statement is often a very clean way to handle discriminated unions.
  • Consider how TypeScript's type inference helps you when working with these unions. When you check the type property, TypeScript automatically knows what specific properties are available within that branch of the union.
Loading editor...
typescript