Discriminated Unions in TypeScript

In this post, we will explore the concept of discriminated unions, which are a way to define union types that have a common property indicating which variant of the type is being used. This property is called the discriminant or tag and can be used to restrict the set of possible values for a union type. Discriminated unions are very useful for representing different scenarios or states in a system and enable writing more readable and robust code with TypeScript.


A discriminated union is composed of members that have a common field, called the discriminant, which serves to distinguish between different cases. The discriminant can be a common property or a literal type. Depending on the value of the discriminant, TypeScript can infer and automatically check the types in different parts of the code.


Let's take a look at an example to better understand. Suppose we want to model different geometric shapes, such as circles, squares, and triangles. We can use a discriminated union for this:


interface Circle {
      kind: 'circle';
      radius: number;
}
interface Square {
      kind: 'square';
      sideLength: number;
}
interface Triangle {
      kind: 'triangle';
      base: number;
      height: number;
}
type Shape = Circle | Square | Triangle;


In this example, we have three interfaces representing each desired geometric shape. Each interface has a 'kind' property that acts as the discriminant. The value of 'kind' is a string literal identifying the specific type of geometric shape.


Now, we can write a function that works with 'Shape' objects and uses the discriminant to make decisions based on the type of geometric shape:


function area(shape: Shape): number {
      switch (shape. Kind) {
          case 'circle':
              return Math.PI * shape.radius ** 2;
          case 'square':
              return shape.sideLength ** 2;
          case 'triangle':
              return (shape. Base * shape. Height) / 2;
      }
}


Notice how TypeScript is able to infer the correct type within each branch of the 'switch' based on the value of the discriminant. This allows us to access the correct properties of each type without the need to manually check types.


The use of discriminated unions offers some important advantages. Firstly, it makes the code more readable and expressive, as we can use the discriminant to clearly distinguish the different cases we are dealing with. Additionally, TypeScript helps prevent type errors by ensuring that the correct properties are accessed in each specific case.


It's important to mention that the use of discriminated unions is not limited to string literal properties. We can use other literal types, such as numbers or booleans, as discriminants. Furthermore, it's also possible to add additional properties to each type in the discriminated union, in addition to the common discriminant.


In summary, discriminated unions are a powerful technique in TypeScript for modeling union types in a safe and expressive way. They allow us to differentiate between different cases of a union based on a shared discriminant, making it easier to write more readable code and avoiding type errors.

Comments

Popular posts from this blog

Exploring the '>>>' Operator in TypeScript: Unsigned Right Shift and Its Applications

Understanding NodeList

querySelector