2 Topics
Chapter•50 Minutes

Enums, Literal Unions, as const, and satisfies

Choose representations for fixed sets of values and validate object shapes while preserving useful inference.

Enums and Their Trade-offs

Enums create named sets of values. Numeric enums have reverse mappings in emitted JavaScript, while string enums provide explicit string values. const enum can erase runtime enum objects in some compiler configurations, but it has tooling and publishing trade-offs, so library authors should understand how consumers compile the output.

For many application states, a string literal union plus a constant object is simpler and interoperates naturally with JSON. Choose an enum when its runtime representation and semantics are valuable, not merely because other languages use enums.

Literal union as an alternative
const Direction = {
  Up: "up",
  Down: "down",
  Left: "left",
  Right: "right"
} as const;

type Direction = typeof Direction[keyof typeof Direction];

function move(direction: Direction) {
  console.log(direction);
}
💡 as const preserves the values as literals, and typeof Direction[keyof typeof Direction] creates the union of those values. The object remains available at runtime.
Key Takeaways
  • Enums have runtime behavior depending on their kind and compiler settings.
  • Literal unions work naturally with JSON string values.
  • as const preserves literal values for type derivation.
Knowledge Check

What is one benefit of a string literal union for API states?

as const and satisfies

as const tells TypeScript to infer the narrowest literal types and mark object properties/arrays readonly in the type system. The satisfies operator checks that an expression conforms to a target type while retaining the expression's more specific inferred type. This is particularly useful for configuration objects where you want validation without losing literal information.

Neither construct validates data at runtime. They also do not make objects deeply immutable at runtime. Use runtime schema validation for data from APIs, storage, environment variables, or user input.

Validate a config while preserving literals
type RouteName = "home" | "docs";

const routes = {
  home: "/",
  docs: "/documentation"
} as const satisfies Record<RouteName, string>;

const docsPath = routes.docs; // inferred as "/documentation"
💡 satisfies checks that all required route keys exist and their values are strings. as const keeps the exact path literals, so routes.docs is not widened to a general string.
Key Takeaways
  • satisfies checks compatibility without replacing the inferred expression type.
  • as const preserves literals and readonly typing.
  • Neither feature performs runtime data validation.
Knowledge Check

How does `satisfies` differ from a direct type annotation in many cases?