How to define a const array in typescript

While the accepted answer is correct, it does have a drawback.

const readonlyArray = [1, 2, 3] as const;

let x = 4; // function parameter, etc.
// Argument of type 'number' is not assignable to parameter of type '1 | 2 | 3'.ts(2345)
// if (readonlyArray.includes(x)) {}

One alternative is to use readonly:

const readonlyArray: readonly number[] = [1, 2, 3];

let x = 4;
if (readonlyArray.includes(x)) {} // OK

// Property 'push' does not exist on type 'readonly number[]'.ts(2339)
// readonlyArray.push(4);

After debugging, I found it is not TypeScript compiler problem, it is because I used a third-party component call DayPicker:

          <DayPicker
            onDayClick={this.handleDayClick}
            selectedDays={posts.day}
            months={MONTHS}
            weekdaysShort={WEEKDAYS_SHORT}
            firstDayOfWeek={1}/>

the type of the prop weekdaysShort is not string[], but [string, string, string, string, string, string, string]

weekdaysShort?: [string, string, string, string, string, string, string];

so TS compile says string[] doesn't match [string, string, string, string, string, string, string].

finally, I just changed the type from string[] to any to avoid this anoy error message, of course, we can change to [string, string, string, string, string, string, string] as well (too long).


Assert your array declaration as const;

const readonlyArray = [1, 2, 3] as const;

Additionally, accessing the element type of a readonly array is trivial:

type Element = typeof readonlyArray[number]` // 1 | 2 | 3

as const assertions work on any declarations, including objects and deeply nested data structures. You can even assert an expression as const. For instance, if the value 1 is inferred as a number, but you want to supply the number literal type, simply assert it 1 as const. The feature was introduced in TypeScript 3.4. You can also reference the docs.

Bear in that a readonly or const array is often called a tuple (as is the case in Python - reference). Tuples can have elements of the same type or elements of entirely different types. Notice, that in the above example the Element type was not inferred as number but as a union of number literals. This is possible because the elements of the tuple are never going to change. It is practical to infer the narrowest possible type. You can, for example, use the number literal type 1 anywhere where a number is required, but you cannot use the number type where the number literal type 1 is required.

A tuple of two elements is often called a pair and may be represented as a product. Although the product of [number, string] is not a number, you can still multiply them together. Because both string and number are infinitely large themselves, so is their product type. Consider simpler example of [1 | 2 | 3, 'a' | 'b' | 'c'], which is equal to:

  [1, 'a']
| [1, 'b']
| [1, 'c']
| [2, 'a']
| [2, 'b']
| [2, 'c']
| [3, 'a']
| [3, 'b']
| [3, 'c']

Further reading:

  • readonly and const
  • Product Types