# O que são 'const assertions' no TypeScript? O famoso 'as const'

O que são const assertions? Você sabe a diferença entre o estranho 'const as const' e o Object.freeze?

- URL: https://blog.lsantos.dev/entenda-o-que-e-as-const-no-typescript/
- Published: 2024-04-24
- Updated: 2026-07-16
- Category: typescript
- Tags: typescript
- Language: pt
- Author: Lucas Santos

---
Esse artigo é um complemento ao meu vídeo com o mesmo tema! Veja ele aqui:

![](https://www.youtube.com/watch?v=CTGqhST9Fjc)

Se você está codando em TypeScript, provavelmente já se deparou com um tipo muito estranho, o famoso `const as const`, algo assim:

```ts
const foo = {
  bar: 'string'
} as const
```

Inclusive, a gente até chegou a falar dele quando falamos sobre [enums](/enums-no-typescript/) aqui no blog. Você pode imaginar que, por ter um `as`, isso deve ser algum tipo de type casting, ou seja, estamos trocando um tipo pelo outro e forçando o TS a aceitar isso, o que é uma má prática. Mas não!

Este tipo de técnica é chamada de [**const assertions**](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#const-assertions) e, como o nome diz, é uma asserção, ou seja, estamos dando mais informações sobre um tipo para o TypeScript. Mas o que estamos dizendo para ele?

## Objetos e arrays

Esse tipo de asserção é geralmente utilizado com objetos e arrays, e também é a forma mais simples de entender o conceito. Mas imagine que você tenha esse objeto:

```ts
const args = [1, 2]
const sum = (a, b) => a+b
```

Tudo que o TS sabe é que `args` é um array de números então ele vai tipar como `number[]`, o que é aceitável, porque você poderia, por exemplo, fazer um `array.push(0)` e ele aceitaria sem problemas, na verdade, na maioria dos casos isso é o que acontece. Mas tem um caso que não.

Existem várias funções no JavaScript que precisam de um número exato de argumentos, um exemplo é a função `Math.atan2` que recebe exatamente 2 parâmetros. Outro exemplo é a nossa função de soma. Então esse código não funciona:

```ts
const args = [1, 2]
const sum = (a, b) => a+b
sum(...args)
```

Porque o TS não consegue inferir a quantidade de parâmetros que args tem, e nem o total de itens presentes no array, justamente porque podemos adicionar, remover ou modificar o array da forma que quisermos.

Se a gente quiser dizer que esse array é imutável, uma constante, temos que usar uma **const assertion**

```ts
const args = [1, 2] as const
const sum = (a, b) => a+b
sum(...args)
```

Neste caso, `args` agora é tipado como `readonly [1, 2]`, ou seja, não podemos modificar o array, e ele tem exatamente dois elementos, 1 e 2. Portanto podemos passar para a função porque dizemos para o TS que ele sempre vai ter dois elementos.

O mesmo é válido para objetos, se passarmos um objeto qualquer como este:

```ts
const obj = {
  foo: 1,
  bar: 'formacaots.com.br'
}
```

O TypeScript vai simplesmente tipá-lo como um objeto dessa forma:

```ts
const obj: {
    foo: number;
    bar: string;
}
```

E podemos adicionar ou remover chaves, além de poder passar qualquer string e qualquer número, ou até mesmo mudar o tipo do objeto, mas se usarmos

```ts
const obj = {
  foo: 1,
  bar: 'formacaots.com.br'
} as const
```

Nossa tipagem muda para:

```ts
const obj: {
    readonly foo: 1;
    readonly bar: "formacaots.com.br";
}
```

Veja que agora ele não é só imutável, mas também tem os tipos literais como chaves. E você pode estar se perguntando: _"E o Object.freeze? Não faz a mesma coisa? Não é até mais seguro por que está em runtime?"_

Existe uma diferença fundamental entre o `Object.freeze` e o `as const`, enquanto o `Object.freeze` vai sim deixar o objeto imutável em tempo de execução, ele só faz isso para o primeiro nível de chaves, então chaves internas e compostas como:

```ts
const foo = {
  bar: {
    baz: 1
  }
}
```

Não funcionam, se você usar `Object.freeze(foo)`, isso garante que `bar` não pode sofrer a alteração para outro objeto, mas `foo.bar.baz` pode ser alterado normalmente. Já o `as const` faria o objeto inteiro ser imutável.

## Conclusão

**const assertions** fazem três coisas:

-   Em tipos primitivos (string, number, boolean, etc), vai remover a possibilidade de _type widening_, ou seja, um `'foo'` virar `string`.
-   Propriedades de objetos se tornam `readonly`
-   Arrays se tornam tuplas imutáveis (`readonly`)

Você pode inclusive usar `as const` em retornos de função, para fazer com que o tipo inferido da função seja sempre inferido como o tipo mais estático possível:

```ts
function foo () {
  return [1, 2] as const // retorna uma tupla
}
```
