TypeScript `Satisfies` keyword—New TypeScript 4.9 feature
Tags: typescript, javascript, webdev, node
Published: 2022-11-11 17:32:30

(You can find a video version of this article on [YouTube](https://www.youtube.com/watch?v=7vHKeFrwvYk)! 📺)
{% youtube 7vHKeFrwvYk %}

## The problem

Imagine you're faced with the following problem:

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

```typescript
type City = CityName | CityCoordinates;
```

`CityName` is a string representing one of the specified cities:

```typescript
type CityName = "New York" | "Mumbai" | "Lagos";
```

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

```typescript
type CityCoordinates = {
  x: number;
  y: number;
};
```

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

```typescript
type User = {
  birthCity: City;
  currentCity: City;
};
```

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 👇

```typescript
const user: User = {
  birthCity: "Mumbai",
  currentCity: { x: 6, y: 3 },
};
```

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:

```typescript
// yields this TypeScript error 👇
// Property 'toUpperCase' does not exist on type 'City'.
//   Property 'toUpperCase' does not exist on type 'CityCoordinates'.
user.birthCity.toUpperCase();
```

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 👇

```typescript
const user = {
  birthCity: "Mumbai",
  currentCity: { x: 6, y: 3 },
} satisfies User
```

The inferred type of the `user` variable is going to be 👇

```typescript
{
  birthCity: "Mumbai";
  currentCity: {
    x: number;
    y: number;
  }
}
```

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 👇

```typescript
// 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);
```

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 👇🏻

```typescript
const user = {
  // assigning "Beijing" yields this error 👇
  //   Type '"Beijing"' is not assignable to type 'City'
  birthCity: "Beijing",
  currentCity: { x: 6, y: 3 },
} satisfies User
```

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](https://www.typescriptlang.org/play?ts=4.9.0-dev.20221020#code/PTAEE8HsFdQCwIYDcCmoGgC7gA5oAYDCAltvlopqAMYIB2oARigFAigqlwoBOoRpcADkEAWxTlIfAdkKQpAE2J0EmFAGd8LbHlAlsoALx7BI8aAA+J2fJ5KVa9QG4WbMDOFiJoYuvSh1TB5lAHNQHhQcCPUUOkxQt1BIOjRIADMKDTRqUmINbVw0fU9zYwAiIRQAd1AATSkAazLLUDKAWWhRRgRiZqsygBkEEMh1MpdEjzlFZVUNcl90BkhGACsUaioqrkmAD3J6BX5wcijIPB54jVAFWMh4uhDEzG4aW3s5v3SIGD4AG0gtAeBV0xWmdlmjiMoAA3ixQKBdgAuUB0TrMHguBHgFForq8FwAXwmiQAdOTDpl+ABVGI8cg6NCIdSTRjES5wAaA1TEZIHOhHfDUaA8CJxLlA3l0fAAGkSjHucCSGSqcGI1CVCAiP1gjP4Ep5fJBaFpvGhcIRbI5xRRxSxNBFYswNus4CJE2oyUCoGgdJRpr4xgtTHZLxd7XRPTKcoRwtFsWdghRMMRKIAbDKICiAMygQly4muT10b1WsOCak4C60GLQ328UlluDFUmYSCVi6EBAxAAUAEoScXvfWeAAmc3wkPWpOtDpdKMxh3xuIulPI0AZrOgXP5liEgI89RpPJ+ANFr1UJvFDu8GsocfGEejxuh5uCVvtqu8Lu9gcsIA).

If you liked this tutorial, you can also check out and subscribe to my [YouTube channel](https://www.youtube.com/channel/UCE7h4of6ywpAG87KXHV6UrQ). Or/and subscribe to my newsletter to get notified when I publish new articles [on my website](https://tomdohnal.com/posts/typescript-satisfies-keyword)!