CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-runtypes

Runtime validation for static types

Pending
Overview
Eval results
Files

literals.mddocs/

Literal Types

Validates exact literal values using SameValueZero equality. Literal types are essential for creating strict value constraints and union types with specific allowed values.

Capabilities

Literal

Creates a validator that accepts only the exact specified value.

/**
 * Validates that a value is exactly equal to the specified literal value
 * Uses SameValueZero equality (same as Map/Set)
 * @param value - The exact value to validate against
 * @example Literal("hello").check("hello") // "hello"
 * @example Literal(42).check(42) // 42
 * @example Literal(true).check(false) // throws ValidationError
 */
function Literal<T extends LiteralValue>(value: T): Runtype<T>;

type LiteralValue = undefined | null | boolean | number | bigint | string;

Usage Examples:

import { Literal, Union } from "runtypes";

// String literals
const StatusActive = Literal("active");
const StatusInactive = Literal("inactive");

// Number literals  
const Zero = Literal(0);
const FortyTwo = Literal(42);

// Boolean literals
const True = Literal(true);
const False = Literal(false);

// Special value literals
const Null = Literal(null);
const Undefined = Literal(undefined);

// BigInt literals
const BigZero = Literal(0n);
const LargeBigInt = Literal(123456789012345678901234567890n);

Enum-like Patterns

Create enum-like validation using unions of literals.

import { Literal, Union } from "runtypes";

// Status enum
const Status = Union(
  Literal("draft"),
  Literal("published"), 
  Literal("archived")
);

type StatusType = Static<typeof Status>; // "draft" | "published" | "archived"

// HTTP Methods
const HttpMethod = Union(
  Literal("GET"),
  Literal("POST"),
  Literal("PUT"),
  Literal("DELETE"),
  Literal("PATCH")
);

// Numeric enum  
const Priority = Union(
  Literal(1),
  Literal(2),
  Literal(3)
);

// Usage
const userStatus = Status.check("published"); // "published"
const method = HttpMethod.check("GET"); // "GET"
const priority = Priority.check(2); // 2

Configuration Objects

Use literals for configuration with specific allowed values.

import { Literal, Union, Object } from "runtypes";

const DatabaseConfig = Object({
  host: String,
  port: Number,
  ssl: Union(Literal(true), Literal(false)), // explicit boolean literals
  logLevel: Union(
    Literal("error"),
    Literal("warn"), 
    Literal("info"),
    Literal("debug")
  ),
  connectionPool: Union(
    Literal("single"),
    Literal("pooled"),
    Literal("cluster")
  )
});

// Usage
const config = DatabaseConfig.check({
  host: "localhost",
  port: 5432,
  ssl: true,
  logLevel: "info",
  connectionPool: "pooled"
});

Discriminated Unions

Create discriminated unions using literal types for type discrimination.

import { Literal, Union, Object } from "runtypes";

const SuccessResponse = Object({
  type: Literal("success"),
  data: Unknown,
  timestamp: Number
});

const ErrorResponse = Object({
  type: Literal("error"), 
  message: String,
  code: Number
});

const LoadingResponse = Object({
  type: Literal("loading"),
  progress: Number.optional()
});

const ApiResponse = Union(SuccessResponse, ErrorResponse, LoadingResponse);

type ApiResponseType = Static<typeof ApiResponse>;
// {
//   type: "success";
//   data: unknown;
//   timestamp: number;
// } | {
//   type: "error";
//   message: string;
//   code: number;
// } | {
//   type: "loading";
//   progress?: number;
// }

// Usage with type narrowing
function handleResponse(response: unknown) {
  const validResponse = ApiResponse.check(response);
  
  switch (validResponse.type) {
    case "success":
      // TypeScript knows this is SuccessResponse
      console.log("Data:", validResponse.data);
      break;
    case "error":
      // TypeScript knows this is ErrorResponse  
      console.error(`Error ${validResponse.code}: ${validResponse.message}`);
      break;
    case "loading":
      // TypeScript knows this is LoadingResponse
      console.log("Loading...", validResponse.progress);
      break;
  }
}

Literal Edge Cases

import { Literal } from "runtypes";

// NaN handling (uses SameValueZero equality)
const NaNLiteral = Literal(NaN);
NaNLiteral.check(NaN); // passes - NaN === NaN with SameValueZero

// Zero handling  
const PositiveZero = Literal(0);
const NegativeZero = Literal(-0);
PositiveZero.check(-0); // passes - 0 === -0 with SameValueZero

// String vs Number distinction
const StringFive = Literal("5");
const NumberFive = Literal(5);
StringFive.check(5); // throws - "5" !== 5
NumberFive.check("5"); // throws - 5 !== "5"

Combining with Other Types

import { Literal, Union, Object, Array } from "runtypes";

// Optional literal values
const Theme = Union(Literal("light"), Literal("dark")).optional();

// Arrays of literals
const Permissions = Array(Union(
  Literal("read"),
  Literal("write"), 
  Literal("admin")
));

// Objects with literal constraints
const User = Object({
  name: String,
  role: Union(Literal("user"), Literal("admin"), Literal("moderator")),
  preferences: Object({
    theme: Union(Literal("light"), Literal("dark")),
    language: Union(Literal("en"), Literal("es"), Literal("fr")),
    notifications: Literal(true).or(Literal(false))
  })
});

type UserType = Static<typeof User>;
// {
//   name: string;
//   role: "user" | "admin" | "moderator";  
//   preferences: {
//     theme: "light" | "dark";
//     language: "en" | "es" | "fr";
//     notifications: boolean;
//   };
// }

Install with Tessl CLI

npx tessl i tessl/npm-runtypes

docs

composite.md

constraints.md

contracts.md

index.md

literals.md

primitives.md

results.md

templates.md

union-intersect.md

utilities.md

validation.md

tile.json