Question

TypeScript String Enums: Create Enums with String Values

Question

TypeScript enums can use numeric values:

enum E {
  Hello = 1,
  World = 2,
}

E.Hello;
E.World;

How can I create an enum whose members have string values, such as "hello" and "world", and access them in the same way?

Short Answer

You will learn how to declare and use string enums in TypeScript. You will also see how string enums differ from numeric enums, how to validate string input safely, and when a string-literal union may be a simpler alternative.

Concept

An enum defines a fixed set of named choices. A string enum gives every choice a readable string value.

enum Greeting {
  Hello = "hello",
  World = "world",
}

Each member has two useful parts:

  • The member name, such as Greeting.Hello
  • The stored string value, such as "hello"
const message: string = Greeting.Hello;
console.log(message); // "hello"

String enums are useful when a value is sent to an API, stored in a database, shown in logs, or placed in a URL. Unlike a numeric value such as 1, a value such as "pending" is understandable without looking up its meaning.

In current TypeScript, string enum members must be initialized with string literals or other constant enum members. They cannot be automatically generated in the way numeric enum members can.

Mental Model

Think of an enum as a labeled control panel.

  • Greeting.Hello is the labeled button you press in code.
  • "hello" is the value that button sends out.

The label prevents spelling variations throughout the program. Instead of repeatedly typing strings like "in-progress", you use one named, checked choice: Status.InProgress.

Take Quiz

Syntax and Examples

Use enum, give each member a name, and assign a string value with =.

enum Status {
  Pending = "pending",
  Active = "active",
  Completed = "completed",
}

const currentStatus: Status = Status.Active;

console.log(currentStatus); // "active"
console.log(Status.Completed); // "completed"

Status is both:

  • A type that represents the allowed enum members.
  • A runtime object that contains values such as Status.Active.

A function can require one of the enum's values:

enum Role {
  Admin = "admin",
  Editor = "editor",
  Viewer = "viewer",
}

function canDeletePosts(role: Role): boolean {
  return role === Role.Admin;
}

canDeletePosts(Role.Admin); // true
canDeletePosts(Role.Viewer); // false

Use PascalCase names for enum types and member names by convention. The string values themselves are usually lowercase when they are API or storage identifiers.

Step by Step Execution

Consider this example:

enum DeliveryState {
  Preparing = "preparing",
  Shipped = "shipped",
  Delivered = "delivered",
}

const state: DeliveryState = DeliveryState.Shipped;

if (state === DeliveryState.Shipped) {
  console.log("Your package is on its way.");
}

Step by step:

  1. DeliveryState declares three named states.
  2. DeliveryState.Shipped evaluates to the string "shipped".
  3. The variable state stores that enum value.
  4. The if condition compares state with DeliveryState.Shipped.
  5. Both values are "shipped", so the condition is true.
  6. The message is printed.

Although the runtime value is a string, using DeliveryState.Shipped makes the intent clear and avoids repeating the raw string.

Real World Use Cases

String enums are especially useful when the value must remain readable outside TypeScript.

  • API requests and responses: represent values such as "admin", "editor", and "viewer".
  • Order workflows: track "pending", "paid", "shipped", and "cancelled".
  • Database fields: store a known category or state as a stable text value.
  • Application configuration: select environments such as "development", "staging", and "production".
  • UI filters: represent sorting choices such as "newest" or "price_low_to_high".
  • Logging and analytics: use readable event types such as "user_signed_in".

Example of an API payload:

enum PaymentStatus {
  Pending = "pending",
  Paid = "paid",
  Failed = "failed",
}

const payload = {
  orderId: "ORD-1042",
  paymentStatus: PaymentStatus.Paid,
};

// Sent as: { orderId: "ORD-1042", paymentStatus: "paid" }
Take Quiz

Real Codebase Usage

In real projects, enums are often used at boundaries: places where your application communicates with users, APIs, databases, files, or configuration.

Prefer named members over raw strings

enum Environment {
  Development = "development",
  Production = "production",
}

function connect(environment: Environment) {
  if (environment === Environment.Production) {
    console.log("Using production settings");
  }
}

Use guard clauses for invalid values

External input is not automatically safe merely because your internal code uses an enum. Validate values received from JSON, query parameters, or forms.

enum SortOrder {
  Newest = "newest",
  Oldest = "oldest",
}

function isSortOrder(value: string): value is SortOrder {
  return Object.values(SortOrder).includes(value as SortOrder);
}

function getSortOrder(value: string): SortOrder {
  if (!isSortOrder(value)) {
    return SortOrder.Newest;
  }

  return value;
}

Use exhaustive switch statements

When handling every state, a switch makes each case visible.

enum TicketStatus {
  Open = "open",
  Closed = "closed",
}

function statusLabel(status: TicketStatus): string {
  switch (status) {
    case TicketStatus.Open:
      return "Open";
    case TicketStatus.Closed:
      return "Closed";
  }
}

Common Mistakes

Expecting automatic string values

Numeric enums can auto-increment, but string enums need explicit values.

// Invalid: string enum members need initializers
enum Color {
  Red,
  Blue,
}

Fix it by assigning every string value:

enum Color {
  Red = "red",
  Blue = "blue",
}

Using a raw string where an enum value is expected

enum Role {
  Admin = "admin",
  User = "user",
}

function setRole(role: Role) {}

setRole("admin"); // Avoid this; use the enum member.

Use:

setRole(Role.Admin);

This keeps call sites consistent and protects against typos.

Assuming string enums support reverse lookup

Numeric enums provide reverse mappings, but string enums do not.

enum Direction {
  Up = "UP",
}

console.log(Direction.Up); // "UP"
// Direction["UP"] is not a reliable reverse lookup for a string enum.

If you need to test whether external input is valid, use Object.values(Direction).includes(...) and a type guard.

Confusing the member name with its stored value

enum Status {
  InProgress = "in_progress",
}

console.log(Status.InProgress); // "in_progress", not "InProgress"

The member name is for TypeScript code. The assigned string is the runtime value.

Forgetting that untrusted input needs validation

A value from an HTTP request may be any string. Do not blindly assert it is an enum value with as Status; check it first.

Comparisons

FeatureString enumNumeric enumString-literal union
ExampleStatus.Active = "active"Status.Active = 0type Status = "active" | "inactive"
Runtime object existsYesYesNo
Readable in JSON and logsYesUsually noYes
Auto-incrementing membersNoYesNot applicable
Reverse mappingNoYesNo
Best forStable named external valuesCompact internal numeric categoriesLightweight type-only fixed strings

A string-literal union is a common alternative when you only need type checking and do not need an enum object at runtime:

type Theme = "light" | "dark";

function setTheme(theme: Theme) {
  console.log(theme);
}

setTheme("dark");

Use a string enum when named runtime constants such as Theme.Dark improve readability. Use a union when the direct strings are already simple and sufficient.

Take Quiz

Cheat Sheet

// Declare a string enum
enum Status {
  Pending = "pending",
  Active = "active",
}

// Read a value
const value = Status.Pending; // "pending"

// Use it as a type
function update(status: Status) {}
update(Status.Active);

// Validate an external string
function isStatus(value: string): value is Status {
  return Object.values(Status).includes(value as Status);
}

Rules:

  • Assign an explicit value to every string enum member.
  • Use EnumName.MemberName instead of duplicating raw strings.
  • String enums do not have numeric enum reverse mapping.
  • Validate strings received from outside the application.
  • Choose stable string values if they will be stored or sent through an API.

FAQ

Can TypeScript enums have string values?

Yes. Assign a string literal to every member:

enum Size {
  Small = "small",
  Large = "large",
}

Why does a string enum member need an initializer?

TypeScript cannot automatically generate meaningful string values. Numeric members can increment from a number, but strings must be explicitly chosen.

How do I get the string value from a TypeScript enum?

Access the member:

enum Mode {
  Dark = "dark",
}

const value = Mode.Dark; // "dark"

Can I convert a string to a string enum?

Only after validation. Check that the string exists in Object.values(MyEnum) before treating it as an enum value.

Do string enums have reverse mappings?

No. Unlike numeric enums, you cannot reliably look up a member name from the stored string using bracket notation.

Should I use a string enum or a union type?

Use a string enum when named runtime constants are helpful. Use a string-literal union when you only need a type and want less generated JavaScript.

Can enum values contain spaces or hyphens?

Yes, the assigned string can contain them:

enum SortOrder {
  PriceLowToHigh = "price-low-to-high",
}

The enum member name must still be a valid TypeScript identifier unless written as a quoted property name.

Take Quiz

Mini Project

Description

Build a small order-status utility for an online store. It uses a string enum so status values are readable in API payloads and consistently handled inside the application.

Goal

Create and validate order statuses, then return a user-friendly message for each valid status.

Requirements

Define an OrderStatus string enum with Pending, Paid, Shipped, and Cancelled values.

Create a function that checks whether an incoming string is a valid order status.

Create a function that returns a message for each order status.

Use a safe default message when an incoming status is invalid.

Take Quiz

Keep learning

Related questions

View more