How to write a constant in the TypeScript?
Tags: typescript, javascript, webdev
Published: 2022-01-05 09:15:44

## Introduction

TypeScript was designed as a superset of JavaScript, so TS types should not affect JS’s runtime. However there’s couple ways to define constant value.

## Object as const:

```typescript
export const BUTTON_SIZES = {
  SMALL: 'small',
  MEDIUM: 'medium',
  LARGE: 'large',
} as const;
```

`as const` will be removed in the compilation time, so only an object will exists in the run time. Adding as const will change type definition from:

```typescript
{ 
  SMALL: string,
  MEDIUM: string,
  LARGE: string,
}
```

into:

```typescript
{
  readonly SMALL: 'small',
  readonly MEDIUM: 'medium',
  readonly LARGE: 'large',
}
```

Looks pretty simple however it wouldn’t be so easy to create a type definition of `BUTTON_SIZES` value.

```typescript
type ButonSizeKey = keyof typeof BUTTON_SIZES; // "SMALL" | "MEDIUM" | "LARGE"
type ButonSizeValue = typeof BUTTON_SIZES[ButonSizeKey] // "small" | "medium" | "large"
```

## Enum:

```typescript
export enum BUTTON_SIZES_ENUM {
  SMALL = 'small',
  MEDIUM = 'medium',
  LARGE = 'large',
};
```

Looks similar to the previous case however this code will be complied into:


```typescript
export var BUTTON_SIZES_ENUM;
(function (BUTTON_SIZES_ENUM) {
  BUTTON_SIZES_ENUM["SMALL"] = "small";
  BUTTON_SIZES_ENUM["MEDIUM"] = "medium";
  BUTTON_SIZES_ENUM["LARGE"] = "large";
})(BUTTON_SIZES_ENUM || (BUTTON_SIZES_ENUM = {}));
```

It’s the same object as in previous case but it takes more space in the final bundle.

Big advantage is the fact that you don’t have to create a separate type for a ButtonSizeValue because enum `BUTTON_SIZE` can be use as a type of a value.

But what about case when enum has numbers instead of strings:

```typescript
export enum PLACE {
  FIRST = 1,
  SECOND = 2,
};
```

Will be complied to:

```typescript
export var PLACE;
(function (PLACE) {
  PLACE[PLACE["FIRST"] = 1] = "FIRST";
  PLACE[PLACE["SECOND"] = 2] = "SECOND";
})(PLACE || (PLACE = {}));
```

And this code it the same that:

```typescript
{1: "FIRST", 2: "SECOND", FIRST: 1, SECOND: 2}
```

So value become a key and key becomes a value…

## Const enum:

```typescript
export const enum BUTTON_SIZES_CONST_ENUM {
  SMALL = 'small',
  MEDIUM =  'medium',
  LARGE = 'large',
};
```
Almost the same code as in the previous example will be removed in compilation time.

Usage of enum like this:

```typescript
const buttonSizeUsage = BUTTON_SIZES_CONST_ENUM.MEDIUM;
```

Will be complied into:

```typescript
const buttonSizeUsage = "medium" /* MEDIUM */;
```

Looks much better than previous example however there’s couple od disadvantages:

```typescript
const obj = { buttonSize: BUTTON_SIZES_CONST_ENUM } // ERROR: 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
Object.values(BUTTON_SIZES_CONST_ENUM); // ERROR 'const' enums can only be used in property or index access expressions or the right hand side of an import declaration or export assignment or type query.
```

## Union:

The simplest way will be:

```typescript
type BUTTON_SIZES_UNION = "small" | "medium" | "large";
```

Type definition will be removed in compilation time and complier will prevent us to pass unknown or different strings.

```typescript
let fn = (buttonSize: BUTTON_SIZES_UNION) => {};
fn('small');
fn('smal'); // Argument of type '"smal"' is not assignable to parameter of type 'BUTTON_SIZES_UNION'
let str: string;
fn(str); // Argument of type 'string' is not assignable to parameter of type 'BUTTON_SIZES_UNION'.
```

Is fast in the implementation but has the same disadvantages as `const enum`. Also changing value (e.g. “medium” into “regular”) requires modification of each usage, not just one like in `enum`/`const enum`.

## Summary:

Is hard to choose the best way, all of them have advantages and disadvantages. In my opinion `const enum` can be good first choice.

[Playground](https://www.typescriptlang.org/play/?#code/PTAEHkCMCsFMGMAuAoWAPADgewE6NPFgHYDO+AQgKoAq14AcgPoDKAkgFoCizoAvKAG9kASGYBZAIIAZKQC5QAchIBbAIYAbdQoA0IsZwAirSmPkLlsACYBLAK7KdIqRIBKAcU5n1qnAHNYjgC+oKokBMRkANzIyIgAnhiwoADSsHF8oADWaVgAZqDxiXmgVLQMLBzcsQlJAGoatkn8hbDFpXRMbFzMANqpcQC6MSCgnET2qJi4+LDjyiU0HRXdjJz0JoIi4tJSGUpqmo7C+kYb-IoWNvZHzu6ce95+AbrBMejYeKCz9qAACs4AYXuQlAoNAADFWC5mNQMgBGXRg0DMTgAhgGDIAJhewzAAIi+DGE3e03CpBmcwWZU6lWYjDR9Bhq3WYk2okkMj2Kg0Wl0x0MxlZ53MVjsDj5tw8Dx8-iC0WQhHJoEgtkQiGIzGsAC9YJQSKp-Bl2uUutx6QwmWsTAA6E6C+WKsigLAwDICZWq9VETU6+TGmkrBmWlmgQIxKBwJDWgBuDVgJAAFP7lmag9RmSYAJTykaUIjWYjVRJUpamumUeisBgZABE3M0NdAAB9QDXLmLGy2a49-DX5epYPhckQMgmVWqNdrYH7FibaYwK1X6Jm+AA+QSBaLDhP7HkKbPIbe7rQHgf4Mg4eQX6xEXxbogJi-ZoA)