Getting started with the TypeScript satisfies operator
Tags: typescript, webdev
Published: 2023-05-10 14:19:59

**Written by [Temitope Oyedele](https://blog.logrocket.com/author/temitopeoyedele/)✏️**

The [TypeScript](https://blog.logrocket.com/tag/typescript/) `satisfies` operator is one of the features released in [TypeScript v4.9](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-4-9.html). It's a new and better approach to [type-safe configuration](https://blog.logrocket.com/write-type-safe-css-modules/) in TypeScript. The `satisfies` operator aims to give developers the ability to assign the most specific type to expressions for inference. In this article, we'll take a closer look at the TypeScript `satisfies` operator and how to use the `satisfies` operator. 

_Jump ahead:_

*   [What is the TypeScript `satisfies` operator?](#typescript-satisfies-operator)
    *   [Life before the `satisfies` operator](#life-before-satisfies-operator)
*   [Introducing the `satisfies` operator](#introducing-satisfies-operator)
    *   [Property name constraining](#property-name-constraining)
    *   [Property name fulfillment](#property-name-fulfillment)
    *   [Property value conformance](#property-value-conformance)
*   [The benefits of using the `satisfies` operator](#benefits-using-satisfies-operator)

## What is the TypeScript `satisfies` operator? <a name="typescript-satisfies-operator">

The `satisfies` operator is a feature in TypeScript that allows you to check if a given type satisfies a specific interface or condition. In other words, it ensures that a type has all the required properties and methods of a specific interface. It is a way to ensure a variable fits into a definition of a type. To learn more about types in TypeScript, visit our [Types vs. interfaces in TypeScript](https://blog.logrocket.com/types-vs-interfaces-typescript/) guide.

### Life before the `satisfies` operator <a name="life-before-satisfies-operator">

Let's look at an example to understand why the TypeScript `satisfies` operator is intriguing and what problems it solves. Let’s create a type `MyState` that's going to be a union of two properties, as shown below:

```typescript
type MyState = StateName | StateCordinates;
```

Here, we are creating a type of `MyState` that will be `StateName` or `StateCordinates`. This means `MyState` is a [union type](https://blog.logrocket.com/understanding-discriminated-union-intersection-types-typescript/) that will be `StateName` or `StateCordinates`. Then, we’ll define our `StateName` as a string with three values. So, our `StateName` can be either `Washington`, `Detroit`, or `New Jersey`, as shown below:

```typescript
type StateName = "Washington" | "Detriot" | "New Jersey";
```

The next step is to define our `StateCordinates` with the following code:

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

Our `StateCordinate` is an object that has two properties, `x` and `y`. The `x` and `y` properties are going to be numbers. Now, we have our type `StateName` (a string) and `StateCordinates`, (an object). Finally, let’s create our type `User` with the code below:

```typescript
type User = {
  birthState: MyState;
  currentState: MyState;
};
```

Our type `User` has two properties, `birthState` and `currentState`. Both of these properties are of type `MyState`. This means that each of these properties can be a `StateName` or `StateCoordinates`. Next, we’re going to create a variable `user` using the code below:

```typescript
const user:User = {
  birthState: "Washington",
  currentState: { x: 8, y: 7 },
};
```

In the code above, the `user` will have the `birthState` property set to the `"Washington"` string as one of the values for the `StateName` type. The `CurrentState` property is set to an object with property `x` with the value of `8` and property `y` of `7`, corresponding to the `StateCordinates`. 

So, this is a perfectly valid way to create and annotate the `user` variable. Imagine we want to access the `birthState` variable and convert it to uppercase, like so:

```typescript
user.birthState.toUpperCase();
```

If we hover our mouse over `toUpperCase()`, TypeScript will throw in an error stating that `"property toUpperCase() does not exist on type MyState and property to uppercase does not exist on type StateCordinates"`, as shown below: ![An Example of the Problems Before the Satisfies Operator in TypeScript](http://blog.logrocket.com/wp-content/uploads/2023/04/problem-before-typescript-satisfies-operator.png) 

This is because TypeScript is not sure of the value of `MyState` or whether it is a string or an object because we defined `MyState` as a union of a string and an object. Essentially, it can be any of them. In order to remove this error, we need to manually validate the property before we can use the `string` method, like so:

```typescript
if (typeof user.birthState === "string") {
  user.birthState.toUpperCase();
}
```

Here, we are writing a condition to check if it is a string, and if it is, then we can use the `string` method. Because we tested it as a string, the TypeScript error should disappear. Having to always validate whether it is a string can be frustrating and cumbersome. This is where the `satisfies` operator comes in.

## Introducing the `satisfies` operator <a name="introducing-satisfies-operator">

While life before the `satisfies` operator required you to always validate whether the property was a string or not, with the `satisfies` operator, you don’t have to do this. Instead of defining the `user` variable manually, we can delete it and replace it with the `satisfies` operator, like so:

```typescript
const user = {
  birthState: "Washington",
  currentState: { x: 7, y: 8 },
} satisfies User;
  user.birthState.toUpperCase();
```

The full code now looks like this:

```typescript
type MyState = StateName | StateCordinates;
type StateName = "Washington" | "Detriot" | "New Jersey";
type StateCordinates = {
  x: number;
  y: number;
};
type User = {
  birthState: MyState;
  currentState: MyState;
};
const user = {
  birthState: "Washington",
  currentState: { x: 8, y: 7 },
} satisfies User;
user.birthState.toUpperCase();
```

The `satisfies` operator prevalidates all the object properties for us, and the TypeScript error no longer pops up. Now, the `satisfies` operator will validate our `user` properties for us. Not only that, but it will also check in advance if any of the properties contain a string or an object. 

Thanks to the `satisfies` operator; TypeScript knows that our `birthState` is a string and not an object because it has prevalidated/checked the values of all properties of the `User`. And, if we try adding something else to the `birthState` property that doesn’t correspond to any of the defined types, we’ll get an error. 

The `satisfies` keyword ensures that we only pass whatever satisfies the `User` type to the `user` variable, allowing TypeScript to do its type [inference magic](https://blog.logrocket.com/types-vs-interfaces-typescript/#:~:text=code%20more%20readable.-,Interfaces%20in%20TypeScript,-In%20TypeScript%2C%20an). Let’s look at some other examples.

### Property name constraining

We can also use the `satisfies` operator to tell the [TypeScript](https://blog.logrocket.com/exploring-advanced-compiler-options-typescript/) [compiler](https://blog.logrocket.com/exploring-advanced-compiler-options-typescript/) that it's OK for an object to include only a subset of the given `keys` but not accept others. Here’s an example:

```typescript
type Keys = 'FirstName' |"LastName"| "age"|"school"| "email"
const student = {
  FirstName: "Temitope",
  LastName: "Oyedele",
  age: 36,
  school:"oxford",
}satisfies Partial<Record<Keys, string | number>>;

student.FirstName.toLowerCase();
student.age.toFixed();
```

By using the `satisfies` operator in the code above, we instruct the TypeScript compiler that the type of the `student` object must match the `PartialRecordKeys, string | number>> type`. The `Partial` type in TypeScript is an inbuilt type that helps manipulate other user-defined types.

### Property name fulfillment

Similar to property name constraining, with the exception that in addition to restricting objects to only contain specific properties, we can also ensure that we get all of the `keys` using the `satisfies` operator. Here’s what that looks like:

```typescript
type Keys = 'FirstName' |"LastName"| "age"|"school"

const student = {
  FirstName: "Temitope",
  LastName: "Oyedele",
  age: 36,
  school:"oxford",
}satisfies Record<Keys, string | number>;

student.age.toFixed();
student.school.toLowerCase();
```

Here, we use the `satisfies` operator with the `Record<Keys, string | number>` to check that an object has all the keys specified by the `Keys` type and has a value of either `string` or `number` type associated with each `key`.

### Property value conformance

The `satisfies` operator is not only capable of restricting the names of properties in an object, but it can also restrict the values of those properties. Suppose we have a `library` object with various books, each represented as an object with properties for the book's `title`, `author`, and `year of publication`. However, we mistakenly used a string instead of a number for the `year of publication` of the book `"Pride and Prejudice"`. 

To catch this error, we can use the `satisfies` operator to ensure that all properties of the `library` object are of `type Book`, which we defined as an object with the required `"title"`, `"author"`, and `"year"` properties, where `"year"` is a number. Here’s what that looks like:

```typescript
type Book = { title: string, author: string, year: number };

const library = {
  book1: { title: "Things fall apart", author: "Chinua Achebe", year: 1958 },
  book2: { title: "Lord of the flies", author: "William Golding", year: 1993 },
  book3: { title: "Harry Potter", author: "J.k Rowling", year: "1997" }, // Error
} satisfies Record<string, Book>;
```

With the help of the `satisfies` operator, the TypeScript compiler can find the error and prompt us to correct the `year property` of the book `"Harry Potter"`.

## The benefits of using the `satisfies` operator <a name="benefits-using-satisfies-operator">

The `satisfies` operator allows us to improve the quality and scalability of our code. However, the `satisfies` operator's main benefits are type safety, code correctness, validation, code reusability, and code organization.

### Type safety

The `satisfies` operator ensures that types have all the necessary methods and properties, ultimately reducing the likelihood of runtime problems. You may catch type problems at build time or before your code is run by using the `satisfies` operator.

### Code correctness

We can use the `satisfies` operator to ensure the correctness of code because it allows us to check if a given type satisfies a particular condition.

### Validation

The `satisfies` operator enables us to verify that an expression's type matches another type without declaring a new variable or casting the expression to a different type.

### Code reusability

Using the `satisfies` operator helps ensure that different parts of our application can consistently work with the same types of data. This helps to make code more modular and reusable.

### Code organization

Using the TypeScript `satisfies` operator helps organize your code into logical blocks based on the type of a value. This can help eliminate repeated type checks in various sections of your code and make it easier to read and comprehend.

## Conclusion

The TypeScript `satisfies` operator is convenient and can help improve the quality and scalability of your code. It does the heavy lifting by prevalidating our values, giving us a more flexible and precise [type-checking experience](https://blog.logrocket.com/type-checking-typerunner/). We can also use the `satisfies` operator to create more robust and maintainable code.

---

##[LogRocket](https://lp.logrocket.com/blg/typescript-signup): Full visibility into your web and mobile apps

[![LogRocket Signup](https://blog.logrocket.com/wp-content/uploads/2017/03/1d0cd-1s_rmyo6nbrasp-xtvbaxfg.png)](https://lp.logrocket.com/blg/typescript-signup)

[LogRocket](https://lp.logrocket.com/blg/typescript-signup) is a frontend application monitoring solution that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page and mobile apps.

[Try it for free](https://lp.logrocket.com/blg/typescript-signup).