Menu
×
   ❮   
HTML CSS JAVASCRIPT SQL PYTHON JAVA PHP HOW TO W3.CSS C C++ C# BOOTSTRAP REACT MYSQL JQUERY EXCEL XML DJANGO NUMPY PANDAS NODEJS DSA TYPESCRIPT ANGULAR GIT POSTGRESQL MONGODB ASP AI R GO KOTLIN SASS VUE GEN AI SCIPY CYBERSECURITY DATA SCIENCE INTRO TO PROGRAMMING BASH RUST

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 1 | 2 | 3
  • 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:

// 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...
Try it Yourself »


Numeric Literal Types

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

// 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}`);
Try it Yourself »

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:

// 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"
Try it Yourself »

Literal Types with Objects

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

// 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);
Try it Yourself »

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:

// 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 ..."
Try it Yourself »

Best Practices

Do's and Don'ts

Do:

  • 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

Don't:

  • 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

Performance Considerations

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



×

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail:
sales@w3schools.com

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail:
help@w3schools.com

W3Schools is optimized for learning and training. Examples might be simplified to improve reading and learning. Tutorials, references, and examples are constantly reviewed to avoid errors, but we cannot warrant full correctness of all content. While using W3Schools, you agree to have read and accepted our terms of use, cookie and privacy policy.

Copyright 1999-2025 by Refsnes Data. All Rights Reserved. W3Schools is Powered by W3.CSS.