Tudo sobre o novo operador satisfies no TypeScript
Tags: typescript, javascript
Published: 2022-10-21 10:56:26

---
title: Tudo sobre o novo operador satisfies no TypeScript
published: true
date: 2022-10-05 13:00:52 UTC
tags: typescript,javascript
canonical_url: https://blog.lsantos.dev/ts-satisfies/
cover_image: https://raw.githubusercontent.com/khaosdoctor/blog-assets/master/images/2022/10/Blog-cover-Template.png
---

No último beta aberto do TypeScript, os devs mostraram o que virá na versão 4.9 da linguagem. Além de algumas otimizações, que são bastante comuns, na inferência de tipos, vamos ter um novo operador na linguagem, o `satisfies`. Bora entender um pouco mais como esse operador vai funcionar.

## O `satisfies`

Quando estamos desenvolvendo com TS, costumamos cair em um dilema complicado. A inferência de tipos do TS é muito boa e específica, então é legal termos essa inferência super específica, mas ao mesmo tempo, essa inferência não leva em consideração alguns fatores, como o nome de chaves.

No exemplo que tiramos do próprio [anúncio do beta](https://devblogs.microsoft.com/typescript/announcing-typescript-4-9-beta/#the-satisfies-operator), temos uma ideia muito boa do que isso significa, vamos imaginar o seguinte, temos um tipo que pode ser ou uma string ou uma tupla RGB, ou seja, temos que ter um `[number, number, number]`, podemos fazer dessa forma:

```
const palette = {
  red: [255, 0, 0],
  green: "#00ff00",
  bleu: [0, 0, 255]
// ^^^ temos um typo aqui
}
```

A inferência automática do tipo do TS vai ser que `palette` é:

```
{
  red: [255, 0, 0],
  green: "#00ff00",
  bleu: [0, 0, 255]
}
```

Ou seja, temos um tipo literal. Esses tipos permitem que usemos determinadas funções para cada tipo de dados em certos casos, por exemplo, uma função `toUpperCase` em `green` já que é uma string, e um `.at(0)` no `red` que é um array:

```
// Conseguimos usar métodos de array aqui
const redComponent = palette.red.at(0);

// Mas não aqui, porque só podemos usar strings
const greenNormalized = palette.green.toUpperCase();
```

Só que perdemos a inferência do nome das chaves, veja que temos um typo, deveríamos ter escrito `blue` e não `bleu`, mas para corrigir isso teríamos que criar um novo tipo mais genérico e dizer para o TS que aquele tipo é o tipo do objeto, nesse caso o tipo poderia ser:

```
type Colors = "red" | "green" | "blue"
type RGB = [red: number, green: number, blue: number]

const palette: Record<Colors, string | RGB> = {
  red: [255, 0, 0],
  green: "#00ff00",
  bleu: [0, 0, 255]
}
```

Isso vai nos dar o erro `Object literal may only specify known properties, and 'bleu' does not exist in type 'Record<Colors, string | RGB>'.`, que é esperado, ou seja, estamos batendo as chaves com o objeto, então podemos corrigi-lo:

```
const palette: Record<Colors, string | RGB> = {
  red: [255, 0, 0],
  green: "#00ff00",
  blue: [0, 0, 255]
}
```

Vamos ter um tipo como esse:

```
{
  red: string | RGB,
  green: string | RGB,
  bleu: string | RGB
}
```

Mas agora a gente vai ter dois erros bem chatos nas duas funções de baixo:

```
// Property 'at' does not exist on type 'string | RGB'.
const redComponent = palette.red.at(0);

// Property 'toUpperCase' does not exist on type 'string | RGB'.
const greenNormalized = palette.green.toUpperCase();
```

O primeiro porque não temos `.at` em strings e o segundo porque não temos `.toUpperCase` em `RGB`, e isso só acontece porque, quando dizemos para o TS que aquele objeto é de um determinado tipo, esse tipo vai generalizar o que vai entrar nesse objeto, por exemplo, nesse caso ele está em dúvida se cada chave é uma string ou array de números, e ai não sabemos inferir as duas coisas.

Para resolver esse problema teríamos que fazer uma conversão explícita:

```
nent = (palette.red as RGB).at(0);
const greenNormalized = (palette.green as string).toUpperCase();
```

E é para isso que o `satisfies` existe. Poderíamos manter a especificação mais detalhada, enquanto dizemos que ela deve seguir algum tipo de molde. Por exemplo:

```
const palette = {
  red: [255, 0, 0],
  green: "#00ff00",
  blue: [0, 0, 255]
} satisfies Record<Colors, string | RGB>
```

Agora o novo tipo de `palette` vai ser:

```
{
    red: [number, number, number];
    green: string;
    blue: [number, number, number];
}
```

Veja como agora estamos usando o poder da inferência específica com o poder da inferência de tipos declarada para poder tirar o máximo proveito do TypeScript. Dessa forma vamos poder usar funções que são string dentro de chaves que são string e funções de arrays dentro de chaves numéricas.

## Conclusão

Essa é, sem dúvida uma das melhores inclusões do superset nos últimos tempos. Acredito que a principal recomendação a partir de agora seja escrever todos os seus tipos sem nenhum tipo de asserção manual, e utilizar o satisfies para poder dizer a qual objeto ele deve pertencer, dessa forma conseguimos manter o melhor de todos os mundos.

Para mais exemplos, dê uma olhada na [issue que propôs essa funcionalidade](https://github.com/microsoft/TypeScript/issues/47920).