Skip to content

Commit

Permalink
[flow][docs] add docs for as const
Browse files Browse the repository at this point in the history
Summary: Changelog: [internal]

Reviewed By: SamChou19815

Differential Revision: D67115228

fbshipit-source-id: 5514bc383036546241f7dabb07127156966c9a57
  • Loading branch information
panagosg7 authored and facebook-github-bot committed Dec 12, 2024
1 parent 8e5ecac commit ab16bba
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 0 deletions.
78 changes: 78 additions & 0 deletions website/docs/types/const-expression.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
---
title: Const Expressions
slug: /types/const-expression
---

Sometimes it is useful to specifiy that a literal expression is expected to be immutable.
In such cases, you can annotate the expression with the `as const` modifier. We
refer to these expressions as const-expressions.

## Typing for Const Expressions {#toc-const-expression-typing}

The inferred type of const-expressions is the [singleton type](../literals) for primitive values
and the read-only versions for container types. Array literals are inferred as tuple types.

Here are some examples of primitive values:
```js
42 as const; // inferred type is 42

"hello" as const; // inferred type is "hello"
```

Containers become read-only and the modifier is applied deeply
```js
{ f: 42 } as const; // {+f: 42}

[42, "hello"] as const; // $ReadOnly<[42, "hello"]>

{ f: { g: 42 } } as const; // {+f: {+g: 42}}
```

Note that the effect of the modifier does not persist through variables. For example
in
```js
const nonConstObject = { g: 42 };
const constObject = { f: nonConstObject } as const;
```
the type of `nonConstObject` will be `{g: number}` and the type of `constObject` will
be `{+f: {g: number}}`. In other words, only the top-level property `prop` will
be read-only.

Finally, it is an error to apply `as const` to non-literal expressions:
```js flow-check
const x = 1;
const y = x as const;
```

## Typical const-expression example {#toc-const-expression-example}

A common pattern where const-expressions are useful is in enum-like
structures that are not expected to be mutated. For example
```js
export const STATUS = {
INIT: 'INIT',
LOADING: 'LOADING',
SUCCESS: 'SUCCESS',
ERROR: 'ERROR',
} as const;
```
The type of `STATUS.INIT` is `"INIT"`, the type of `STATUS.LOADING` is `"LOADING"` and so on.

With this definition it is also possible to effectively lift the values of the various fields
to type annotations. For example
```js
type State =
| { +kind: typeof STATUS.INIT; }
| { +kind: typeof STATUS.LOADING; progress: number; }
| { +kind: typeof STATUS.SUCCESS; result: string; }
| { +kind: typeof STATUS.ERROR; msg: string; };
```
Without the use of `as const` the type `typeof STATUS.INIT` would be `string`, which
would make it unsuitable as a distinguishing tag in a disjoint union.

## Adoption of `as const` syntax
To use the `as const` syntax, you need to upgrade your infrastructure:
- Flow and Flow Parser: 0.256+
- Prettier: 3.1+
- Babel: use the [babel-plugin-syntax-hermes-parser](https://www.npmjs.com/package/babel-plugin-syntax-hermes-parser) plugin version 0.19+, see our [Babel guide](../../tools/babel) for more details.
- ESLint: use [hermes-eslint](https://www.npmjs.com/package/hermes-eslint) plugin version 0.19+, see our [ESLint guide](../../tools/eslint) for more details.
1 change: 1 addition & 0 deletions website/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ module.exports = {
'types/type-guards',
'types/typeof',
'types/casting',
'types/const-expression',
'types/utilities',
'types/modules',
'types/comments',
Expand Down

0 comments on commit ab16bba

Please sign in to comment.