Typescript Tricks: Defining Types from Arrays


Typescript

When working with TypeScript, it’s common to need a type that represents a union of specific string values. There’s a useful technique for this.

Consider a scenario where you have a set of known string constants, such as feature flags, status codes, or a list of allowed options. A common approach is to define them in an array:

const flags = ["a", "b", "c"];

To create a type representing one of these strings – “a”, “b”, or “c” – you could define it manually:

type Flag = "a" | "b" | "c";

This approach works, but if the array changes, the type definition must also be updated. This introduces a risk of inconsistencies and requires manual synchronization.

The as const assertion offers a solution. Appending as const to an array definition instructs TypeScript to treat the array and its contents as literal and immutable.

const flags = ["a", "b", "c"] as const;

Using as const, TypeScript infers the type of flags as readonly ["a", "b", "c"] instead of string[]. Each element is then treated as its own literal type.

This allows the union type to be derived directly from the constant array:

type Flag = (typeof flags)[number];

Here’s an explanation of the syntax:

  • typeof flags: This operator returns the type of the flags constant, which is readonly ["a", "b", "c"].
  • [number]: This is an indexed access type. When applied to an array or tuple type, it yields a union of the types of its elements.

Consequently, (typeof flags)[number] resolves to "a" | "b" | "c". This creates a type that is synchronized with the array. If a new flag, such as “d”, is added to the flags array (with as const), the Flag type will automatically include “d”.

This technique is useful for maintaining a single source of truth for a set of related string constants and their corresponding union type. It promotes the DRY (Don’t Repeat Yourself) principle and reduces the likelihood of errors when the constants are modified.

© 2025 Marian Lambert