runtypes
Version:
Runtime validation for static types
189 lines (188 loc) • 8.9 kB
TypeScript
import type Array from "./Array.js";
import type BigInt from "./BigInt.js";
import type Boolean from "./Boolean.js";
import Brand from "./Brand.js";
import Constraint from "./Constraint.js";
import type Function from "./Function.js";
import type InstanceOf from "./InstanceOf.js";
import Intersect from "./Intersect.js";
import Literal from "./Literal.js";
import type Never from "./Never.js";
import type Number from "./Number.js";
import type Object from "./Object.js";
import Optional from "./Optional.js";
import Parser from "./Parser.js";
import type Record from "./Record.js";
import type Spread from "./Spread.js";
import type String from "./String.js";
import type Symbol from "./Symbol.js";
import type Template from "./Template.js";
import type Tuple from "./Tuple.js";
import Union from "./Union.js";
import type Unknown from "./Unknown.js";
import type Result from "./result/Result.js";
declare const RuntypeSymbol: unique symbol;
declare const RuntypeConformance: unique symbol;
declare const RuntypePrivate: unique symbol;
/**
* Obtains the static type associated with a runtype.
*/
type Static<R extends {
readonly [RuntypeSymbol]: [unknown, unknown];
}> = R[typeof RuntypeSymbol][0];
/**
* Obtains the parsed type associated with a runtype.
*/
type Parsed<R extends {
readonly [RuntypeSymbol]: [unknown, unknown];
}> = R[typeof RuntypeSymbol][1];
/**
* A runtype determines at runtime whether a value conforms to a type specification.
*/
declare class Runtype<T = any, X = T> implements Conformance<T, X> {
#private;
tag: string;
/** @internal */ readonly [RuntypeSymbol]: [T, X];
/** @internal */ readonly [RuntypeConformance]: Conformance<T, X>[typeof RuntypeConformance];
/** @internal */ private readonly [RuntypePrivate];
get [globalThis.Symbol.toStringTag](): string;
toString(): string;
/** @internal */ static create: <R extends Runtype>(validate: (context: Context<R> & {
innerValidate: InnerValidate;
memoParsed?: WeakMap<object, object>;
}) => Result<Static<R> | Parsed<R>>, base: Runtype.Base<R>) => R;
/** @internal */ private constructor();
/**
* Process a value with this runtype, returning a detailed information of success or failure. Does not throw on failure.
*/
inspect<U, P extends boolean = true>(x: U, options?: {
/**
* Whether to parse.
*
* @default true
*/
parse?: P | undefined;
}): Result<P extends true ? X : Validated<T, U>>;
/**
* Validates that a value conforms to this runtype, returning the original value, statically typed. Throws `ValidationError` on failure.
*/
check<U = T>(x: Target<T, U, this>): Validated<T, U>;
/**
* Validates that a value conforms to this runtype, returning a `boolean` that represents success or failure. Does not throw on failure.
*/
guard<U = T>(x: Target<T, U, this>): x is Validated<T, U>;
/**
* Validates that a value conforms to this runtype. Throws `ValidationError` on failure.
*/
assert<U = T>(x: Target<T, U, this>): asserts x is Validated<T, U>;
/**
* Validates that a value conforms to this runtype and returns another value returned by the function passed to `withParser`. Throws `ValidationError` on failure. Does not modify the original value.
*/
parse<U = T>(x: Target<T, U, this>): X;
/**
* Returns a shallow clone of this runtype with additional properties. Useful when you want to integrate related values, such as the default value and utility functions.
*/
with<P extends object>(extension: P | ((self: this) => P)): this & P;
/**
* Creates a shallow clone of this runtype.
*/
clone(): this;
/**
* Unions this Runtype with another.
*/
or<R extends Runtype.Core>(other: R): Union<[this, R]>;
/**
* Intersects this Runtype with another.
*/
and<R extends Runtype.Core>(other: R): Intersect<[this, R]>;
/**
* Optionalizes this property.
*
* Note that `Optional` is not a runtype, but just a contextual modifier which is only meaningful when defining the content of `Object`. If you want to allow the validated value to be `undefined`, use `undefinedable` method.
*/
optional(): Optional<this, never>;
/**
* Optionalizes this property, defaulting to the given value if this property was absent. Only meaningful for parsing.
*/
default<X = never>(value: X): Optional<this, X>;
/**
* Unions this runtype with `Null`.
*/
nullable(): Union<[this, Literal<null>]>;
/**
* Unions this runtype with `Undefined`.
*/
undefinedable(): Union<[this, Literal<undefined>]>;
/**
* Unions this runtype with `Null` and `Undefined`.
*/
nullishable(): Union<[this, Literal<null>, Literal<undefined>]>;
/**
* Uses a constraint function to add additional constraints to this runtype, and manually converts a static type of this runtype into another via the type argument if passed.
*/
withConstraint<Y extends X>(constraint: (x: X) => boolean | string): Constraint<this, Y>;
/**
* Uses a guard function to add additional constraints to this runtype, and automatically converts a static type of this runtype into another.
*/
withGuard<Y extends X>(guard: (x: X) => x is Y): Constraint<this, Y>;
/**
* Uses an assertion function to add additional constraints to this runtype, and automatically converts a static type of this runtype into another.
*/
withAssertion<Y extends X>(assert: (x: X) => asserts x is Y): Constraint<this, Y>;
/**
* Adds a brand to the type.
*/
withBrand<B extends string>(brand: B): Brand<B, this>;
/**
* Chains custom parser after this runtype. Basically only works in the `parse` method, but in certain cases parsing is implied within a chain of normal validation, such as before execution of a constraint, or upon function boundaries enforced with `Contract` and `AsyncContract`.
*/
withParser<Y>(parser: (value: X) => Y): Parser<this, Y>;
/**
* Statically ensures this runtype is defined for exactly `T`, not for a subtype of `T`. `X` is for the parsed type.
*/
conform<T, X = T>(this: Conform<T, X>): Conform<T, X> & this;
/**
* Guards if a value is a runtype.
*/
static isRuntype: (x: unknown) => x is Runtype.Interfaces;
/**
* Asserts if a value is a runtype.
*/
static assertIsRuntype: (x: unknown) => asserts x is Runtype.Interfaces;
static [globalThis.Symbol.hasInstance]: (x: unknown) => x is Runtype.Interfaces;
}
declare namespace Runtype {
/** @internal */ type Base<R> = {
[K in keyof R as K extends Exclude<keyof Runtype, "tag"> ? never : K]: R[K];
} & (globalThis.Function | object);
/**
* An upper bound of a {@link Runtype|`Runtype`}, with the bare minimum set of APIs to perform validation and parsing. Useful when you want a variable to accept any runtype; if you want to introspect the contents of it, use {@link Runtype.isRuntype|`Runtype.isRuntype`} or {@link Runtype.assertIsRuntype|`Runtype.assertIsRuntype`} first and `switch` with the {@link Runtype.prototype.tag|`Runtype.prototype.tag`}.
*/
type Core<T = any, X = T> = Pick<Runtype<T, X>, typeof RuntypeSymbol | "tag" | "inspect" | "check" | "guard" | "assert" | "parse">;
/**
* The union of all possible runtypes. {@link Runtype.isRuntype|`Runtype.isRuntype`} or {@link Runtype.assertIsRuntype|`Runtype.assertIsRuntype`} can be used to ensure a value is of this type.
*/
type Interfaces = Array | Array.Readonly | BigInt | Boolean | Brand | Constraint | Function | InstanceOf | Intersect | Literal | Never | Number | Object | Object.Readonly | Parser | Record | String | Symbol | Symbol<string | undefined> | Template | Tuple | Tuple.Readonly | Union | Unknown;
type Spreadable = Runtype.Core<readonly unknown[]> & Iterable<Spread<Spreadable>>;
}
type Conform<T, X> = Runtype.Core<T, X> & Conformance<T, X>;
type Conformance<T, X> = {
/** @internal */ readonly [RuntypeConformance]: [
(StaticTypeOfThis: T) => T,
(ParsedTypeOfThis: X) => X
];
};
type IsGeneric<R extends Runtype.Core> = string extends R["tag"] ? true : false;
type IsAny<T> = boolean extends (T extends never ? true : false) ? true : false;
type Target<T, U, This extends Runtype.Core> = IsAny<T & U> extends true ? any : IsGeneric<This> extends true ? U : [T & U] extends [never] ? T : U;
type Validated<T, U> = IsAny<T & U> extends true ? T : T & U;
type Context<R extends Runtype.Core> = {
expected: R;
received: unknown;
parsing: boolean;
};
type InnerValidate = <T, X>(context: Context<Runtype.Core<T, X>> & {
memoParsed?: WeakMap<object, object>;
}) => Result<T | X>;
export default Runtype;
export type { Static, Parsed };