Ever struggled with handling multiple object shapes in TypeScript and wished for a more type-safe solution?
If so, you're not alone. Many developers are unaware of the full potential that tagged unions (also known as discriminated unions) offer in TypeScript. This powerful feature can enhance your code's safety, readability, and maintainability. In this article, we'll dive deep into tagged unions and explore how they can elevate your TypeScript skills.
Tagged unions allow you to create types that represent one of several possible shapes, each with a distinguishing property known as the "tag" or "discriminator." This enables TypeScript to narrow down types in conditional checks, ensuring that your code handles all possible cases explicitly.
Tagged unions help catch errors at compile time by ensuring all possible cases are handled. This reduces runtime errors and makes your code more robust.
By explicitly defining the shape of each case, your code becomes more readable and easier to maintain. Future developers (or even future you) will thank you!
TypeScript can warn you if you forget to handle a possible case, ensuring that your code accounts for all scenarios.
Consider a scenario where you have different shapes and want to calculate their areas:
// Define interfaces with a discriminant property 'kind' interface Circle { kind: 'circle'; radius: number; } interface Rectangle { kind: 'rectangle'; width: number; height: number; } interface Triangle { kind: 'triangle'; base: number; height: number; } // Create a union type of all shapes type Shape = Circle | Rectangle | Triangle; // Function to calculate the area based on shape kind function calculateArea(shape: Shape): number { switch (shape.kind) { case 'circle': return Math.PI * shape.radius ** 2; case 'rectangle': return shape.width * shape.height; case 'triangle': return (shape.base * shape.height) / 2; default: // The 'never' type ensures all cases are handled const _exhaustiveCheck: never = shape; return _exhaustiveCheck; } }
Tagged unions are incredibly useful in state management scenarios, such as representing the various states of an asynchronous operation (e.g., data fetching).
interface LoadingState { status: 'loading'; } interface SuccessState { status: 'success'; data: string; } interface ErrorState { status: 'error'; error: string; } type AppState = LoadingState | SuccessState | ErrorState; function renderApp(state: AppState) { switch (state.status) { case 'loading': return 'Loading...'; case 'success': return `Data: ${state.data}`; case 'error': return `Error: ${state.error}`; // default case can be omitted because typescript is making sure all cases are covered! } }
Clear Representation of States: Each interface represents a distinct state of the application, making it easy to understand and manage.
Type Safety with Data Access: When the state is 'success', TypeScript knows that state has a data property. Similarly, when the state is 'error', it knows about the error property. This prevents you from accidentally accessing properties that don't exist in a given state.
Exhaustiveness Checking: If you add a new state (e.g., EmptyState with status: 'empty'), TypeScript will alert you to handle this new case in the renderApp function.
Improved Maintainability: As your application grows, managing different states becomes more manageable. Changes in one part of the code prompt necessary updates elsewhere, reducing bugs.
Consistent Discriminator: Use the same property name (e.g., type, kind, or status) across all types.
Literal Types: Ensure the discriminator property uses literal types ('email', 'sms', etc.) for accurate type narrowing.
Avoid String Enums: Prefer string literal types over enums for discriminators to keep type narrowing straightforward.
Tagged unions are a powerful feature in TypeScript that can help you write safer and more maintainable code. By explicitly handling each possible type, you reduce the chance of unexpected errors and make your code easier to understand.
Give tagged unions a try in your current or next TypeScript project and experience the benefits firsthand!
The above is the detailed content of TypeScript Tagged Unions are OP. For more information, please follow other related articles on the PHP Chinese website!