Enums and literal types help you define sets of named constants and specific allowed values. The TypeLand Adventure Game uses enums extensively for movement directions, terrain types, and collectible kinds! Let's explore how they work.
Numeric enums auto-increment from an initial value (default: 0):
// Basic numeric enum (starts at 0)
enum Direction {
North, // 0
East, // 1
South, // 2
West // 3
}
const facingDirection: Direction = Direction.North;
console.log(facingDirection); // 0
// Custom starting value
enum StatusCode {
OK = 200,
BadRequest = 400,
Unauthorized = 401,
NotFound = 404,
ServerError = 500
}
function handleResponse(code: StatusCode): string {
switch (code) {
case StatusCode.OK:
return "Success!";
case StatusCode.NotFound:
return "Resource not found";
default:
return "Error occurred";
}
}
String enums provide more readable values and better debugging:
// String enum (TypeLand uses these!)
enum MovementKey {
NORTH = "NORTH",
SOUTH = "SOUTH",
EAST = "EAST",
WEST = "WEST"
}
enum GroundMaterial {
MEADOW = "MEADOW",
STONE = "STONE",
LAKE = "LAKE",
SAND = "SAND"
}
enum CollectibleKind {
TREASURE_CHEST = "TREASURE_CHEST",
MAGIC_ORB = "MAGIC_ORB",
ANCIENT_SCROLL = "ANCIENT_SCROLL",
CRYSTAL_GEM = "CRYSTAL_GEM"
}
// Using string enums
function canWalkOn(terrain: GroundMaterial): boolean {
return terrain === GroundMaterial.MEADOW ||
terrain === GroundMaterial.SAND;
}
console.log(canWalkOn(GroundMaterial.MEADOW)); // true
console.log(canWalkOn(GroundMaterial.LAKE)); // false
Const enums are removed during compilation for better performance:
// Const enum - inlined at compile time
const enum Color {
Red = "#FF0000",
Green = "#00FF00",
Blue = "#0000FF"
}
// This code:
const bgColor = Color.Red;
const textColor = Color.Blue;
// Compiles to (no enum object created):
const bgColor = "#FF0000";
const textColor = "#0000FF";
// Const enums reduce bundle size
const enum LogLevel {
Debug,
Info,
Warning,
Error
}
String literal types define exact values a variable can have:
// Union of string literals
type Difficulty = "easy" | "normal" | "hard" | "expert";
function setGameDifficulty(level: Difficulty): void {
console.log(`Difficulty set to: ${level}`);
}
setGameDifficulty("normal"); // ✓ OK
// setGameDifficulty("medium"); // ✗ Error - not in the union
// Combine with type aliases
type Alignment = "left" | "center" | "right";
type VerticalAlign = "top" | "middle" | "bottom";
function positionElement(
horizontal: Alignment,
vertical: VerticalAlign
): void {
// Position logic
}
positionElement("center", "middle");
Literal types also work with numbers and booleans:
// Specific number values
type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6;
type BinaryDigit = 0 | 1;
function rollDice(): DiceRoll {
return (Math.floor(Math.random() * 6) + 1) as DiceRoll;
}
// Boolean literals
type Yes = true;
type No = false;
// Mixed literal type
type Port = 3000 | 4000 | 8080 | "auto";
function startServer(port: Port): void {
console.log(`Server starting on port: ${port}`);
}
startServer(3000); // ✓ OK
startServer("auto"); // ✓ OK
// startServer(5000); // ✗ Error
When should you use each?
// Enum approach
enum HttpMethod {
GET = "GET",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE"
}
function request(method: HttpMethod, url: string): void {
// Implementation
}
request(HttpMethod.GET, "/api/users");
// Literal type approach
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
function request(method: HttpMethod, url: string): void {
// Implementation
}
request("GET", "/api/users");
// When to use enums:
// - Need reverse mapping (value to name)
// - Want a runtime object with all values
// - Building a library/framework
// - Want auto-completion without quotes
// When to use literal types:
// - Simpler, more lightweight
// - Better tree-shaking
// - More flexible (can be extended easily)
// - Modern TypeScript recommendation
// From TypeLand's definitions.ts
// Movement directions enum
enum MovementKey {
NORTH = "NORTH",
SOUTH = "SOUTH",
EAST = "EAST",
WEST = "WEST"
}
// Terrain types enum
enum GroundMaterial {
MEADOW = "MEADOW",
STONE = "STONE",
LAKE = "LAKE",
SAND = "SAND"
}
// Collectible types enum
enum CollectibleKind {
TREASURE_CHEST = "TREASURE_CHEST",
MAGIC_ORB = "MAGIC_ORB",
ANCIENT_SCROLL = "ANCIENT_SCROLL",
CRYSTAL_GEM = "CRYSTAL_GEM"
}
// Using enums in the game engine
class AdventureEngine {
private movementDeltas = new Map<MovementKey, [number, number]>([
[MovementKey.NORTH, [-1, 0]],
[MovementKey.SOUTH, [1, 0]],
[MovementKey.EAST, [0, 1]],
[MovementKey.WEST, [0, -1]]
]);
canMove(terrain: GroundMaterial): boolean {
return terrain === GroundMaterial.MEADOW ||
terrain === GroundMaterial.SAND;
}
}
"a" | "b" | "c"