Enums

10 questions found

What is a numeric enum, and what values do its members get by default?

Beginner
A numeric enum assigns sequential integer values starting at 0 to each member by default, unless you explicitly assign a starting value — subsequent members then auto-increment from there.
enum Direction {
  Up,    // 0
  Down,  // 1
  Left,  // 2
  Right  // 3
}
console.log(Direction.Up); // 0
Real-world example Representing a fixed set of directions, statuses, or days of the week with meaningful names instead of magic numbers.

Common follow-ups: What happens if you assign a custom starting value to the first member, like Up = 1?

Primitive Types Arrays & Tuples

What is a string enum, and how does it differ from a numeric enum?

Beginner
A string enum explicitly assigns a distinct string literal to each member (no auto-incrementing), which makes debugging easier since logged/serialized values are meaningful text rather than opaque numbers, and prevents accidental numeric type coercion between unrelated enums.
enum Status {
  Active = 'ACTIVE',
  Inactive = 'INACTIVE',
  Pending = 'PENDING'
}
console.log(Status.Active); // 'ACTIVE'
Real-world example Representing an order or subscription status where the readable string value is also what gets sent to or received from an API.

Common follow-ups: Can string enum members reference other members' values automatically, the way numeric enums can compute from a previous value?

Union & Intersection Types

What is 'reverse mapping' in numeric enums, and why don't string enums support it?

Intermediate
Numeric enums generate a two-way lookup object at runtime — you can go from name to value AND from value back to name (Direction[0] === 'Up'). String enums only generate a one-way object, since having numeric values map back to keys would be ambiguous/meaningless for string values.
enum Direction { Up, Down }
console.log(Direction.Up);   // 0
console.log(Direction[0]);   // 'Up' -- reverse mapping, numeric enums only
Real-world example Converting a stored numeric status code back into its readable name for logging or display purposes.

Common follow-ups: Does this reverse mapping affect the size of the generated JavaScript output?

Primitive Types Arrays & Tuples

What is a 'const enum' and how does it differ from a regular enum in the compiled output?

Intermediate
A const enum is fully inlined at every usage site during compilation and produces NO actual runtime object at all — usages of Direction.Up are replaced directly with the literal value 0 in the emitted JavaScript, resulting in smaller, faster output, at the cost of losing the ability to iterate over enum values at runtime.
const enum Direction { Up, Down }
let d = Direction.Up;
// compiles to roughly: let d = 0; -- no Direction object exists at runtime
Real-world example Using const enums for performance-sensitive, high-frequency code where the small object-creation overhead of a regular enum matters.

Common follow-ups: Why are const enums considered risky or discouraged in some bundler/build setups (like with Babel or isolatedModules)?

tsconfig & Compiler Options

How do computed and constant enum members work when mixing string and numeric-style initialization?

Intermediate
Enum members can be constant (a literal, or computed from prior members) or 'computed' (derived from a non-constant expression) — TypeScript requires that any UNINITIALIZED member following a computed one must have an explicit value, since it can no longer safely auto-increment from an unknown runtime expression.
function getValue() { return 10; }
enum Mixed {
  A = 1,
  B = getValue(), // computed
  // C would need an explicit value here -- can't auto-increment after a computed member
  C = 20
}
Real-world example Rarely needed directly, but useful to understand when debugging why TypeScript demands an explicit value after certain enum members.

Common follow-ups: Why does TypeScript enforce this restriction specifically after computed members?

Primitive Types Arrays & Tuples

Why do many style guides recommend using a union of string literal types instead of an enum in modern TypeScript?

Advanced
Union literal types (`type Status = 'active' | 'inactive'`) require zero runtime code (fully erased, unlike regular enums which generate a real object), work naturally with plain string values from JSON/APIs without any conversion, and integrate more smoothly with generic type inference — enums add real runtime overhead and some quirky edge-case behaviors that literal unions avoid entirely.
// Enum: generates a runtime object, less flexible with raw string values
enum Status { Active = 'ACTIVE', Inactive = 'INACTIVE' }

// Literal union: zero runtime cost, works directly with API string values
type Status = 'ACTIVE' | 'INACTIVE';
Real-world example Choosing a literal union over an enum specifically because API responses already send raw string values that need no conversion.

Common follow-ups: What ergonomic advantages does an actual enum still retain over a literal union, like autocomplete-friendly namespacing?

Union & Intersection Types

How does TypeScript's structural type checking treat two DIFFERENT numeric enums that happen to have the same underlying values?

Advanced
Unlike most structural comparisons, TypeScript treats numeric enum members as NOMINALLY distinct from each other by name even when their underlying values match — you cannot assign a member of one numeric enum to a variable typed as a different numeric enum, even if both equal 0, though plain numbers CAN still be assigned to a numeric enum variable.
enum A { X = 0 }
enum B { Y = 0 }
let a: A = A.X;
// let bad: A = B.Y; // Error: Type 'B' is not assignable to type 'A'
let ok: A = 0; // OK -- plain numbers are still assignable
Real-world example Understanding a confusing compiler error when trying to pass one enum's member where a structurally-identical-looking different enum is expected.

Common follow-ups: Does this same nominal-like distinctness apply to string enums as well?

Structural Typing & Duck Typing

How do you create a type-safe iteration over all values of a string enum?

Advanced
Use Object.values(EnumName) to get an array of the enum's values (safe for string enums, since they don't generate reverse-mapping numeric keys), optionally typed explicitly as an array of the enum type for full type safety when iterating.
enum Status { Active = 'ACTIVE', Inactive = 'INACTIVE' }
const allStatuses = Object.values(Status) as Status[];
allStatuses.forEach(s => console.log(s)); // 'ACTIVE', 'INACTIVE'
Real-world example Populating a dropdown's options dynamically from every possible enum value, without hardcoding the list separately.

Common follow-ups: Why does the same Object.values() approach behave differently (and need filtering) for numeric enums?

Primitive Types Arrays & Tuples

What is an 'ambient enum' declared with 'declare enum', and when would you use one?

Advanced
declare enum describes an enum that ALREADY EXISTS at runtime (typically defined in plain JavaScript or another compiled module) without generating any new runtime code itself — used in .d.ts files to describe a third-party library's runtime enum-like object so TypeScript can type-check code that references it.
// library.d.ts
declare enum Color {
  Red,
  Green,
  Blue
}
// no JS object is generated here -- it must already exist at runtime, provided by the library
Real-world example Writing a declaration file for a JavaScript library that exports an enum-like object, so TypeScript users of that library get type checking.

Common follow-ups: How does this interact with the 'const enum' inlining behavior when the library itself defines a const enum?

Declaration Files

How would you model a set of flags/permissions using a numeric enum with bitwise values, and how do you check if a flag is set?

Advanced
Assign each enum member a distinct power-of-two value so they can be safely combined with the bitwise OR operator into a single number representing multiple flags at once; check whether a specific flag is present using the bitwise AND operator against that flag's value.
enum Permission {
  Read = 1 << 0,   // 1
  Write = 1 << 1,  // 2
  Delete = 1 << 2  // 4
}
const userPerms = Permission.Read | Permission.Write; // 3
const canWrite = (userPerms & Permission.Write) !== 0; // true
Real-world example Representing a user's combined set of permissions (read/write/delete) compactly as a single stored integer.

Common follow-ups: What are the readability trade-offs of bitwise flag enums compared to using an array or Set of permission strings?

Never Unknown & Void Types