bugl
bugl
HomeLearnPatternsPathsSearchPremium
HomeLearnPatternsPaths
Learn/TypeScript/TypeScript Core
TypeScript•TypeScript Core

TypeScript Literal Types

Understanding Literal Types in TypeScript

Literal types in TypeScript allow you to specify exact values that variables can hold, providing more precision than broader types like string or number .

They are the building blocks for creating precise and type-safe applications.

Key Concepts

  • String Literals : Exact string values like "success" | "error"
- Numeric Literals : Specific numbers like 123
  • Boolean Literals : Either true or false
  • Template Literal Types : String literal types built using template string syntax

Common Use Cases

  • Defining specific sets of allowed values
  • Creating discriminated unions
  • Type-safe event handling
  • API response typing
  • Configuration objects

String Literal Types

A string literal type represents a specific string value:

Example

// A variable with a string literal type
let direction: "north" | "south" | "east" | "west";
// Valid assignments direction = "north"; direction = "south"; // Invalid assignments would cause errors // direction = "northeast"; // Error: Type '"northeast"' is not assignable to type '"north" | "south" | "east" | "west"' // direction = "up";        // Error: Type '"up"' is not assignable to type '"north" | "south" | "east" | "west"' // Using string literal types in functions function move(direction: "north" | "south" | "east" | "west") { console.log(`Moving ${direction}`);
}
move("east");  // Valid
// move("up");  // Error: Argument of type '"up"' is not assignable to parameter of type...

Numeric Literal Types

Similar to string literals, numeric literal types represent specific numeric values:

Example

// A variable with a numeric literal type
let diceRoll: 1 | 2 | 3 | 4 | 5 | 6;
// Valid assignments diceRoll = 1; diceRoll = 6; // Invalid assignments would cause errors // diceRoll = 0;      // Error: Type '0' is not assignable to type '1 | 2 | 3 | 4 | 5 | 6' // diceRoll = 7;      // Error: Type '7' is not assignable to type '1 | 2 | 3 | 4 | 5 | 6' // diceRoll = 2.5;    // Error: Type '2.5' is not assignable to type '1 | 2 | 3 | 4 | 5 | 6' // Using numeric literal types in functions function rollDice(): 1 | 2 | 3 | 4 | 5 | 6 {
return Math.floor(Math.random() * 6) + 1 as 1 | 2 | 3 | 4 | 5 | 6;
}
const result = rollDice();
console.log(`You rolled a ${result}`);

Boolean Literal Types

Boolean literal types are less commonly used since there are only two boolean values, but they can be useful in specific scenarios:

Example

// A type that can only be the literal value 'true' type YesOnly = true; // A function that must return true function alwaysSucceed(): true { // Always returns the literal value 'true'
return true;
}
// Boolean literal combined with other types type SuccessFlag = true | "success" | 1; type FailureFlag = false | "failure" | 0; function processResult(result: SuccessFlag | FailureFlag) {
if (result === true || result === "success" || result === 1) {
  console.log("Operation succeeded");
} else {
console.log("Operation failed");
}
}
processResult(true);      // "Operation succeeded"
processResult("success"); // "Operation succeeded"
processResult(1);         // "Operation succeeded"
processResult(false);     // "Operation failed"

Literal Types with Objects

Literal types can be combined with object types to create very specific shapes:

Example

// Object with literal property values type HTTPSuccess = { status: 200 | 201 | 204; statusText: "OK" | "Created" | "No Content"; data: any;
};
type HTTPError = {
  status: 400 | 401 | 403 | 404 | 500;
  statusText: "Bad Request" | "Unauthorized" | "Forbidden" | "Not Found" | "Internal Server Error";
  error: string;
};
type HTTPResponse = HTTPSuccess | HTTPError;
function handleResponse(response: HTTPResponse) {
  if (response.status >= 200 && response.status < 300) {
    console.log(`Success: ${response.statusText}`);
    console.log(response.data);
  } else {
  console.log(`Error ${response.status}: ${response.statusText}`);
  console.log(`Message: ${response.error}`);
}
}
// Example usage
const successResponse: HTTPSuccess = {
  status: 200, statusText: "OK", data: { username: "john_doe", email: "john@example.com" }
};
const errorResponse: HTTPError = {
  status: 404, statusText: "Not Found", error: "User not found in database"
};
handleResponse(successResponse);
handleResponse(errorResponse);

Template Literal Types

TypeScript 4.1+ introduced template literal types, which allow you to create new string literal types by combining existing ones using template string syntax:

Example

// Basic template literals type Direction = "north" | "south" | "east" | "west"; type Distance = "1km" | "5km" | "10km"; // Using template literals to combine them type DirectionAndDistance = `${Direction}-${Distance}`; // "north-1km" | "north-5km" | "north-10km" | "south-1km" | ...
let route: DirectionAndDistance;
route = "north-5km";   // Valid
route = "west-10km";   // Valid
// route = "north-2km";   // Error // route = "5km-north";   // Error // Advanced string manipulation type EventType = "click" | "hover" | "scroll"; type EventTarget = "button" | "link" | "div"; type EventName = `on${Capitalize<EventType>}${Capitalize<EventTarget>}`; // "onClickButton" | "onClickLink" | "onClickDiv" | ... // Dynamic property access type User = { id: number; name: string; email: string; createdAt: Date;
};
type GetterName<T> = `get${Capitalize<string & keyof T>}`;
type UserGetters = {
  [K in keyof User as GetterName<User>]: () => User[K];
};
// { getId: () => number; getName: () => string; ... } // String pattern matching type ExtractRouteParams<T extends string> = T extends `${string}:${infer Param}/${infer Rest}` ? Param | ExtractRouteParams<Rest> : T extends `${string}:${infer Param}` ? Param : never; type Params = ExtractRouteParams<"/users/:userId/posts/:postId">;  // "userId" | "postId" // CSS units and values type CssUnit = 'px' | 'em' | 'rem' | '%' | 'vh' | 'vw'; type CssValue = `${number}${CssUnit}`;
let width: CssValue = '100px';    // Valid
let height: CssValue = '50%';     // Valid
// let margin: CssValue = '10';   // Error // let padding: CssValue = '2ex'; // Error // API versioning type ApiVersion = 'v1' | 'v2' | 'v3'; type Endpoint = 'users' | 'products' | 'orders'; type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE'; type ApiUrl = `https://api.example.com/${ApiVersion}/${Endpoint}`; // Complex example: Dynamic SQL query builder type Table = 'users' | 'products' | 'orders'; type Column<T extends Table> = T extends 'users' ? 'id' | 'name' | 'email' | 'created_at' : T extends 'products' ? 'id' | 'name' | 'price' | 'in_stock' : T extends 'orders' ? 'id' | 'user_id' | 'total' | 'status' : never; type WhereCondition<T extends Table> = { [K in Column<T>]?: { equals?: any; notEquals?: any; in?: any[];
};
};
function query<T extends Table>( table: T, where?: WhereCondition<T> ): `SELECT * FROM ${T}${string}` {
  // Implementation would build the query
  return `SELECT * FROM ${table}` as const;
}
// Usage
const userQuery = query('users', {
  name: { equals: 'John' }, created_at: { in: ['2023-01-01', '2023-12-31'] }
});
// Type: "SELECT * FROM users WHERE ..."

Do's and Don'ts

  • Use literal types for fixed sets of values (enums, configuration options)
  • Combine with union types for better type safety
  • Use template literal types for string pattern matching
  • Leverage type inference when possible
  • Document the meaning of literal types
  • Overuse literal types when a more general type would be better
  • Create extremely large union types that hurt performance
  • Use string literals when an enum would be more appropriate

Type Checking Performance

  • Large union types can slow down type checking
  • Complex template literal types can increase compilation time
  • Consider using type aliases for complex literal types
  • Be mindful of TypeScript's recursion depth limits

Previous

TypeScript Type Inference

Next

TypeScript Namespaces

This chapter

Overview
40

Lessons

241m

Read time

1. TypeScript Tutorial2. TypeScript Introduction3. TypeScript Getting Started4. TypeScript Simple Types5. TypeScript Explicit Types and Inference6. TypeScript Special Types7. TypeScript Arrays8. TypeScript Tuples9. TypeScript Object Types10. TypeScript Enums11. TypeScript Type Aliases and Interfaces12. TypeScript Union Types13. TypeScript Functions14. TypeScript Casting15. TypeScript Classes16. TypeScript Basic Generics17. TypeScript Utility Types18. TypeScript Keyof19. TypeScript Null & Undefined20. TypeScript Definitely Typed21. TypeScript 5.x Updates22. TypeScript Configuration23. TypeScript with Node.js24. TypeScript with React25. TypeScript Tooling26. TypeScript Advanced Types27. TypeScript Type Guards28. TypeScript Conditional Types29. TypeScript Mapped Types30. TypeScript Type Inference31. TypeScript Literal Types32. TypeScript Namespaces33. TypeScript Index Signatures34. TypeScript Declaration Merging35. TypeScript Async Programming36. TypeScript Decorators37. TypeScript in JavaScript Projects (JSDoc)38. TypeScript Migration Guide39. TypeScript Error Handling40. TypeScript Best Practices

On this page

Understanding Literal Types in TypeScriptKey ConceptsCommon Use CasesString Literal TypesNumeric Literal TypesBoolean Literal TypesLiteral Types with ObjectsTemplate Literal TypesDo's and Don'tsType Checking Performance