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:
- Define a
Shapediscriminated union type: This union should include types forCircle,Rectangle, andTriangle. - Each shape type must have a unique literal type discriminant: This will typically be a
typeproperty (e.g.,"circle","rectangle","triangle"). - Define specific properties for each shape:
Circle: Requires aradius.Rectangle: Requireswidthandheight.Triangle: Requiresbaseandheight.
- Implement an
calculateAreafunction: This function should take aShapeas input and return its calculated area as anumber. - Utilize type narrowing: Inside
calculateArea, use control flow (likeifstatements or aswitchstatement) 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 positivenumbertypes. - The
typeproperty for each shape will always be one of the defined literal strings:"circle","rectangle", or"triangle". - The
calculateAreafunction should return anumber.
Notes
- Remember to import
Math.PIfor the circle area calculation. - A
switchstatement 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
typeproperty, TypeScript automatically knows what specific properties are available within that branch of the union.