Runtime validation for static types
—
Validates exact literal values using SameValueZero equality. Literal types are essential for creating strict value constraints and union types with specific allowed values.
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);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); // 2Use 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"
});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;
}
}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"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