DEV Community

Leonardo Ribeiro
Leonardo Ribeiro

Posted on

How to Improve TypeScript Code with the satisfies Operator

If you're working with TypeScript, you may have come across situations where you need to check whether an object implements a certain interface or satisfies a certain set of requirements. This is where the satisfies operator comes in handy. In this article, we'll explore what the satisfies operator is, how it works, and how you can use it to improve your TypeScript code.

What is the satisfies Operator?

The satisfies operator is a new addition to TypeScript, introduced in version 4.9. It allows you to check whether an object satisfies a set of requirements or constraints defined by an interface. Essentially, it checks whether an object conforms to the shape of the interface, even if it doesn't explicitly implement it.

Here's a simple example to illustrate this:


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

const john = {
  name: 'John',
  age: 30,
  occupation: 'Developer'
};

if (john satisfies Person) {
  console.log('John is a Person');
} else {
  console.log('John is not a Person');
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define an interface Person with two properties:name and age. We also define an object john with three properties:name, age, and occupation. We then use the satisfies operator to check whether john satisfies the Person interface. Since john has the same properties as Person, the satisfies operator returns true.

How Does the satisfies Operator Work?

Under the hood, the satisfies operator uses the concept of structural typing, which is a feature of TypeScript that allows you to use objects that have the same shape as a given type or interface, even if they don't explicitly implement it.

When you use the satisfies operator, TypeScript checks whether the object you're testing has all the properties and methods required by the interface you're checking against. If it does, the satisfies operator returns true. Otherwise, it returns false.

Here's an example to illustrate this:


interface Animal {
  name: string;
  sound: string;
}

interface Cat {
  name: string;
  sound: string;
  purr: () => void;
}

const garfield = {
  name: 'Garfield',
  sound: 'Meow',
  purr: () => console.log('Purrrrr')
};

if (garfield satisfies Cat) {
  garfield.purr(); // 'Purrrrr'
} else {
  console.log('Garfield is not a Cat');
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define two interfaces:Animal and Cat. The Cat interface extends the Animal interface and adds a purr method. We also define an object garfield with three properties:name, sound, and purr. We then use the satisfies operator to check whether garfield satisfies the Cat interface. Since garfield has all the properties and methods required by the Cat interface, including the purr method, the satisfies operator returns true.

How to Use the satisfies Operator to Improve Your Code

The satisfies operator can be a powerful tool for improving your TypeScript code. Here are some ways you can use it:

1. Check whether an object implements an Interface

One common use case for the satisfies operator is to check whether an object implements a certain interface. This can be useful when you want to ensure that an object has all the required properties and methods before using it in your code.


interface User {
  name: string;
  email: string;
  age: number;
  isAdmin: boolean;
}

class UserService {
  static updateUser(user: User) {
    if (user satisfies User) {
      // Update user in database
    } else {
      throw new Error('Invalid user object');
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define an interface User with four properties: name, email, age, and isAdmin. We also define a static method updateUser in a UserService class that takes a User object as a parameter. Before updating the user in the database, we use the satisfies operator to check whether the object passed in as an argument satisfies the User interface. If it does, we update the user in the database. If not, we throw an error.

2. Check Whether an Object Satisfies a Set of Requirements

Another use case for the satisfies operator is to check whether an object satisfies a certain set of requirements or constraints. This can be useful when you want to ensure that an object meets certain criteria before using it in your code.


interface Product {
  name: string;
  price: number;
  isAvailable: boolean;
}

function showAvailableProducts(products: Product[]) {
  const availableProducts = products.filter((product) => {
    return product.satisfies({
      name: 'string',
      price: 'number',
      isAvailable: 'boolean'
    });
  });
  console.log(availableProducts);
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define an interface Product with three properties: name, price, and isAvailable. We also define a function showAvailableProducts that takes an array of Product objects as a parameter. Inside the function, we use the filter method to filter out the products that don't satisfy a set of requirements defined by an object literal.

The satisfies operator checks whether each product in the array satisfies the requirements defined by the object literal. If it does, the product is included in the availableProducts array.

3. Check Whether an Object is a Subtype of Another Type

Finally, you can use the satisfies operator to check whether an object is a subtype of another type. This can be useful when you want to ensure that an object can be used in place of another object with a different type.


interface Vehicle {
  brand: string;
  model: string;
  year: number;
}

interface Car extends Vehicle {
  numberOfDoors: number;
}

function startEngine(vehicle: Vehicle) {
  if (vehicle satisfies Car) {
    console.log('Starting car engine');
  } else {
    console.log('Starting generic vehicle engine');
  }
}
Enter fullscreen mode Exit fullscreen mode

In this example, we define two interfaces: Vehicle and Car. The Car Interface extends the Vehicle interface and adds a numberOfDoors property. We also define a function startEngine that takes a Vehicle object as a parameter. Inside the function, we use the satisfies operator to check whether the object passed in as an argument satisfies the Car interface. If it does, we start the car engine. If not, we start the generic vehicle engine.

Conclusion

The satisfies operator is a powerful tool that can help you write more robust and flexible TypeScript code. It allows you to check whether an object implements a certain interface, satisfies a set of requirements, or is a subtype of another type. By using the satisfies operator, you can ensure that your code is more resilient to changes and can handle a wider range of objects with different shapes.

Remember that the satisfies operator is only available in TypeScript 4.9 and above, so make sure to update your TypeScript version if you haven't already. Also, keep in mind that while the satisfies operator can be a useful tool, it should not be used as a replacement for proper type checking and validation in your code.

With the satisfies operator in your toolkit, you can write more flexible and robust TypeScript code that can handle a wider range of objects and scenarios. Happy coding!

Top comments (0)