Skip to content

jamesdbruner/tenums

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Type-safe Enums with Tenum<T>

With Tenum<T>, TypeScript can automatically infer strict, type-safe values, eliminating the need for manual type guards. This ensures that only valid values can be assigned, preventing runtime errors.

The Problem

Traditional TypeScript enums have weak type enforcement and require type guards to validate values at runtime. This makes them unreliable for ensuring strict type safety.

Example: Traditional Enums

enum ColorEnum {
  RED = 'red',
  GREEN = 'green',
  BLUE = 'blue',
}

// TypeScript allows invalid values
const color: ColorEnum = 'yellow' as ColorEnum // No type error, but incorrect

// Requires a manual type guard
function isValidColorEnum(value: unknown): value is ColorEnum {
  return Object.values(ColorEnum).includes(value as ColorEnum)
}

function handleColor(color: ColorEnum): string {
  if (!isValidColorEnum(color)) {
    return 'Invalid color'
  }
  return `Selected color: ${color}`
}

console.log(handleColor('yellow' as any)) // Requires a runtime check

Issues with Traditional Enums

  • TypeScript does not prevent invalid values at compile-time.
  • Requires manual type guards (isValidColorEnum) to validate values.
  • Runtime validation is needed, making the code less safe and performant.

The Solution

With Tenums, TypeScript enforces correctness at compile-time, ensuring that only valid values are used. Invalid values are caught before the code runs.

const Colors = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',
} as const

// Automatically infers "red" | "green" | "blue"
type ColorsType = Tenum<typeof Colors>

function handleColor(color: ColorsType) {
  return `Selected color: ${color}`
}

// Works because "red" is a valid value
console.log(handleColor(Colors.RED)) // "red"

// Compile-time error: Argument of type '"yellow"' is not assignable to parameter of type '"red" | "green" | "blue"'.
console.log(handleColor('yellow'))

Benefits

  • Strict type inference: "red" | "green" | "blue" instead of just string.
  • No runtime validation required—TypeScript enforces correctness at compile-time.
  • Eliminates type guards—invalid values fail before execution.
  • Extracts the strict union of values from an object.

Example Usage

const StatusCodes = {
  OK: 200,
  NOT_FOUND: 404,
  SERVER_ERROR: 500,
} as const

type StatusType = Tenum<typeof StatusCodes>

// Works
const status: StatusType = 200

// Compile-time error: "400" is not assignable to "200 | 404 | 500"
const badStatus: StatusType = 400

TenumKeys<T> Extracts the union of keys from an object while ensuring immutability.

export type TenumKeys<T extends Record<string, unknown>> = keyof Readonly<T>

Example Usage:

const Colors = {
  RED: 'red',
  GREEN: 'green',
  BLUE: 'blue',
} as const

type ColorKeys = TenumKeys<typeof Colors> // "RED" | "GREEN" | "BLUE"

About

Tenums are a zero-runtime overhead solution for defining type-safe enums in TypeScript. It enforces strict values at compile-time, preventing invalid assignments and eliminating the need for manual type guards.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors