How to Use TypeScript Enums with Functions

Say your order tracker passes status codes as plain strings. A typo like "SHIPED" compiles without a peep.

To use TypeScript enums with functions, type each parameter and return value as the enum, like status: OrderStatus. Then only real members get through.

In this tutorial, I’ll build a small order-status module that shows how to use TypeScript enums with functions: typed parameters, an exhaustive switch, a fee lookup, helper methods and input checks.

Here’s what we’re building. It rejects an unknown status and prints a fee for the rest:

VS Code with a TypeScript OrderStatus enum, a Record fee table and a type guard, terminal printing fees and one rejected status
The finished file prints a fee for three valid statuses and rejects LOST.

I compiled each file with --strict and ran it on TypeScript 7.0.2 and Node.js v22.22.2.

Before You Start: the OrderStatus enum

You only need TypeScript and Node.js. Every file below starts with this string enum, so paste it at the top of each one:

enum OrderStatus {
  Pending = "PENDING", Shipped = "SHIPPED",
  Delivered = "DELIVERED", Cancelled = "CANCELLED",
}

String values read well in logs and JSON. The TypeScript enums guide covers numeric enums too.

Step 1: Type a function parameter with the enum

Add a function that takes and returns an OrderStatus:

function nextStatus(status: OrderStatus): OrderStatus {
  if (status === OrderStatus.Pending) return OrderStatus.Shipped;
  if (status === OrderStatus.Shipped) return OrderStatus.Delivered;
  return status; // Delivered and Cancelled stay put
}

console.log(nextStatus(OrderStatus.Pending));
console.log(nextStatus(OrderStatus.Shipped));
console.log(nextStatus(OrderStatus.Cancelled));

Output:

SHIPPED
DELIVERED
CANCELLED
VS Code showing a nextStatus function typed with an OrderStatus enum parameter and return type, terminal printing SHIPPED, DELIVERED and CANCELLED
Each call returns an OrderStatus member.

Checkpoint: you see SHIPPED, DELIVERED and CANCELLED.

Step 2: Make the enum switch exhaustive

The never line in default makes the compiler flag any member your switch forgets. I left out Cancelled on purpose:

function describe(status: OrderStatus): string {
  switch (status) {
    case OrderStatus.Pending: return "Waiting to ship";
    case OrderStatus.Shipped: return "On the truck";
    case OrderStatus.Delivered: return "At the door";
    default: const missed: never = status; return missed;
  }
}

Compiler output:

status_switch.ts(11,20): error TS2322: Type 'OrderStatus.Cancelled' is not assignable to type 'never'.
VS Code underlining missed in a switch over an OrderStatus enum, terminal showing error TS2322 OrderStatus.Cancelled is not assignable to never
The build stops with TS2322 because Cancelled has no case.

Add the missing case above default:

case OrderStatus.Cancelled: return "Refund issued";

Checkpoint: the build passes and all four labels print.

More patterns: switch statements with TypeScript enums.

Step 3: Look up enum values with a Record

Fees don’t need a switch. A Record<OrderStatus, number> maps every member to a number:

const fee: Record<OrderStatus, number> = {
  PENDING: 0, SHIPPED: 7.99, DELIVERED: 7.99, CANCELLED: 0,
};
const total = (subtotal: number, status: OrderStatus): string =>
  `$${(subtotal + fee[status]).toFixed(2)}`;

console.log(total(42.5, OrderStatus.Shipped));
console.log(total(42.5, OrderStatus.Cancelled));

Output:

$50.49
$42.50
VS Code with a Record keyed by an OrderStatus enum and a total function, terminal printing $50.49 and $42.50
A shipped $42.50 order totals $50.49; cancelled stays $42.50.

Checkpoint: two totals print. Drop CANCELLED and tsc fails with TS2741, so no member goes without a fee.

It works for labels too; see TypeScript enums as object keys.

Step 4: Attach functions to the enum with a namespace

Want OrderStatus.isFinal() like a method? A namespace with the same name merges into the enum:

namespace OrderStatus {
  export function isFinal(s: OrderStatus): boolean {
    return s === OrderStatus.Delivered || s === OrderStatus.Cancelled;
  }
}

console.log(OrderStatus.isFinal(OrderStatus.Shipped));
console.log(OrderStatus.isFinal(OrderStatus.Cancelled));
console.log(Object.keys(OrderStatus));

Output:

false
true
[ 'Pending', 'Shipped', 'Delivered', 'Cancelled', 'isFinal' ]
VS Code with a namespace merged into an OrderStatus enum exporting isFinal, terminal showing false, true and a key list that includes isFinal
isFinal now shows up in Object.keys() too.

Important: filter out functions before you loop over the members.

A class can hold the helpers instead; see TypeScript enums in classes.

Test the enum functions on raw input

CSV and API data arrives as plain strings, so the finished file checks each one with a type guard:

const fee: Record<OrderStatus, number> =
  { PENDING: 0, SHIPPED: 7.99, DELIVERED: 7.99, CANCELLED: 0 };
const isStatus = (v: string): v is OrderStatus =>
  Object.values<string>(OrderStatus).includes(v);

for (const raw of ["SHIPPED", "PENDING", "LOST", "DELIVERED"]) {
  console.log(isStatus(raw)
    ? `${raw}: fee $${fee[raw].toFixed(2)}`
    : `${raw}: rejected, not an OrderStatus`);
}

Output:

SHIPPED: fee $7.99
PENDING: fee $0.00
LOST: rejected, not an OrderStatus
DELIVERED: fee $7.99

v is OrderStatus narrows raw in the true branch, so fee[raw] compiles, and LOST gets rejected.

Other options: check if a value exists in a TypeScript enum.

How do you fix enum function errors?

The one I hit most: ship("SHIPPED") on a status: OrderStatus parameter fails with TS2345, because a string literal isn’t assignable to a string enum.

Pass OrderStatus.Shipped, or validate outside data first; see converting a string to an enum in TypeScript.

Where to Take It Next with enum functions

Still on enums? These go deeper:

Frequently asked questions

Can a TypeScript function take an enum as a parameter?

Yes. Type it as status: OrderStatus; only members are accepted.

Can a function return an enum value?

Yes. Set the return type to the enum, as nextStatus() does.

How do I add a method to a TypeScript enum?

Merge a same-name namespace and export functions from it.

How do I write a function that accepts any string enum?

Use a generic, <T extends Record<string, string>>(e: T), and pass the enum object.

Why does passing “SHIPPED” fail for a string enum?

A string literal isn’t assignable to a string enum (TS2345). Pass the member instead.

Where are TypeScript enums documented?