DEV Community πŸ‘©β€πŸ’»πŸ‘¨β€πŸ’»

Cover image for TypeScript `Satisfies` keywordβ€”New TypeScript 4.9 feature
Tom Dohnal
Tom Dohnal

Posted on • Originally published at tomdohnal.com

TypeScript `Satisfies` keywordβ€”New TypeScript 4.9 feature

(You can find a video version of this article on YouTube! πŸ“Ί)

The problem

Imagine you're faced with the following problem:

You have a type City that can be either CityName or CityCoordinates:

type City = CityName | CityCoordinates;
Enter fullscreen mode Exit fullscreen mode

CityName is a string representing one of the specified cities:

type CityName = "New York" | "Mumbai" | "Lagos";
Enter fullscreen mode Exit fullscreen mode

CityCoordinates is an object with x and y properties denoting the coordinates of your city:

type CityCoordinates = {
  x: number;
  y: number;
};
Enter fullscreen mode Exit fullscreen mode

And the User type has birthCity and currentCity, both of which are you type City:

type User = {
  birthCity: City;
  currentCity: City;
};
Enter fullscreen mode Exit fullscreen mode

Then, you want to create a new variable user that adheres to the User type.

You want to assign "Mumbai" to the birthCity property (that's of the type CityName) and { x: 6, y: 3 } to the currentCity property (that's of the type CityCoordinates).

What you would normally do is something like this πŸ‘‡

const user: User = {
  birthCity: "Mumbai",
  currentCity: { x: 6, y: 3 },
};
Enter fullscreen mode Exit fullscreen mode

That's all well and good and, as of TypeScript 4.8 of less, the only way to make sure that the user variable matches the shape of the User type.

Now, say you want to make the birthCity property of the user variable uppercase.

If you were to do that, however, you'd make TypeScript upset and get an error:

// yields this TypeScript error πŸ‘‡
// Property 'toUpperCase' does not exist on type 'City'.
//   Property 'toUpperCase' does not exist on type 'CityCoordinates'.
user.birthCity.toUpperCase();
Enter fullscreen mode Exit fullscreen mode

The way that TypeScript sees the birthCity property is that it can be either CityName or CityCoordinates.

It doesn't "know" that you want the user variable to have the CityName type for the birthCity and the CityCoordinates for the currentCity.

satisfies to the rescue

Before the satisfies keyword was introduced, there wasn't a good way to achieve this.

More specifically, it wasn't possible to both

  1. ensure that a variable matches the specified type
  2. make TypeScript infer a more specific type based on the values provided to this variable

Now that we've got the satisfies keyword, this very thing is now possible!

The syntax is as follows πŸ‘‡

const user = {
  birthCity: "Mumbai",
  currentCity: { x: 6, y: 3 },
} satisfies User
Enter fullscreen mode Exit fullscreen mode

The inferred type of the user variable is going to be πŸ‘‡

{
  birthCity: "Mumbai";
  currentCity: {
    x: number;
    y: number;
  }
}
Enter fullscreen mode Exit fullscreen mode

This will enable us to access string-specific methods (like .toUpperCase()) on the birthCity property and access the x and y number properties on the currentCity variable πŸ‘‡

// we can call `toUpperCase`
user.birthCity.toUpperCase();

// ...and we can access the `x` (or `y`) properties
// and call `number`-specific methods on them
user.currentCity.x.toFixed(2);
Enter fullscreen mode Exit fullscreen mode

And, on top of that, if we were to assign a value that doesn't match the User type to the user variable, we would get protected from type errors πŸ‘‡πŸ»

const user = {
  // assigning "Beijing" yields this error πŸ‘‡
  //   Type '"Beijing"' is not assignable to type 'City'
  birthCity: "Beijing",
  currentCity: { x: 6, y: 3 },
} satisfies User
Enter fullscreen mode Exit fullscreen mode

In conclusion, with satisfies we can get the best of both worlds. Type safety saves us from runtime errors and powerful type inference gives us most specific types for free.

Source code

You can find the source code for this tutorial on Typescript Playground.

If you liked this tutorial, you can also check out and subscribe to my YouTube channel. Or/and subscribe to my newsletter to get notified when I publish new articles on my website!

Top comments (1)

Collapse
 
llorx profile image
Jorge Fuentes

Finally an easy explanation of satisfies. Thank you.

πŸ› See a bug on this page?

Join our team and help us fix it. We're hiring for a Senior Full Stack Engineer β€” Head here to learn more and apply.