Advanced Types in TypeScript - In depth Types Learning in TypeScript

TypeScript has some of the Advanced types, which allow developers to write more expressive and concise code.

In this article, we will discuss four advanced types in TypeScript:

  1. Union types,
  2. Intersection types,
  3. Type aliases and
  4. Type guards.

We will provide examples and demonstrations to help you better understand how these advanced types work in TypeScript.

Union Types

A union type is a type that can hold multiple types. It is denoted using the | symbol. Here’s an example:

function printID(id: string | number) {
  console.log(`ID: ${id}`);
}

printID("12345");
printID(67890);

In this example, we define a function called printID that takes a parameter of type string | number. This means that the parameter can be either a string or a number. Inside the function, we log the ID to the console.

When to use Union type in TypeScript

Union types are useful when you want to accept multiple types of values as input to a function or variable. But as a Good coding practice, sometimes it is recommended to not use Union type as it could break the SOLID principle. But of-course it depends on the case.

Intersection Types

An intersection type is a type that combines multiple types into a single type. It is denoted using the & symbol. Here’s an example:

interface User {
  name: string;
  age: number;
}

interface Employee {
  jobTitle: string;
  salary: number;
}

type EmployeeUser = User & Employee;

const john: EmployeeUser = {
  name: "John",
  age: 30,
  jobTitle: "Software Engineer",
  salary: 80000,
};

console.log(john);

In this example, we define two interfaces: User and Employee. We then create a new type called EmployeeUser that combines the properties of both interfaces using the intersection type operator &. Finally, we create an object called john that conforms to the EmployeeUser type, and log the object to the console.

When to use Intersection type in TypeScript

Intersection types are useful when you want to create a type that combines properties from multiple other types.

Type Aliases

A type alias is a way to create a new name for an existing type. It is denoted using the type keyword.
Here’s an example:

type Age = number;

function printAge(age: Age) {
  console.log(`Age: ${age}`);
}

printAge(30);  // ✅
printAge("Hello"); // ❌

In this example, we define a type alias called Age that is equivalent to the number type. We then define a function called printAge that takes a parameter of type Age. Inside the function, we log the age to the console.

Type aliases are useful when you want to create a more descriptive name for an existing type, or when you want to simplify complex type definitions.

Another Example of a Type Aliases

type status = 'active' | 'inactive';

interface User {
    name: string;
	status: status
}

function checkUser(user: User) {
    const isActiveStatus = User.status === 'active' // ✅
    const isInactiveStatus = User.status === 'inactive' // ✅
    const isOtherStatus = User.status === 'other-status' // ❌
}

That means, we only can check with the specific type of active or inactive when using this type. This is super useful for components where value could be fixed in a range like that.

Type Guards

A type guard is a way to check the type of a variable at runtime. It is typically used in combination with union types to determine which type is currently being used. Here’s an example:

function printValue(value: string | number) {
  if (typeof value === "string") {
    console.log(`String value: ${value}`);
  } else if (typeof value === "number") {
    console.log(`Number value: ${value}`);
  }
}

printValue("Hello"); // ✅
printValue(42); // ✅
printValue(true); // ❌

In this example, we define a function called printValue that takes a parameter of type string | number. Inside the function, we use a type guard to check the type of the parameter. If it is a string, we log a string message to the console. If it is a number, we log a number message to the console.

Type guards are useful when you have a union type and need to determine which specific type is currently being used. They can help prevent errors caused by trying to access properties or methods that do not exist on a particular type.

Conclusion

Advanced types in TypeScript can make your code more concise, expressive, and easier to maintain. Union types and intersection types can help you define more flexible types, while type aliases and type guards can make your code more descriptive and safer.

By understanding these advanced types and how to use them, you can take full advantage of TypeScript’s features and write more robust and maintainable code.

Previous
Modules in TypeScript - Modules in depth in TypeScript
Next
Type vs Interface in TypeScript - When to choose what