Comparing version 1.0.0 to 2.0.0
@@ -1,48 +0,10 @@ | ||
import { Runtype } from './index'; | ||
export interface AsyncContract0<Z> { | ||
enforce(f: () => Promise<Z>): () => Promise<Z>; | ||
import { RuntypeBase } from './runtype'; | ||
export interface AsyncContract<A extends any[], Z> { | ||
enforce(f: (...a: A) => Promise<Z>): (...a: A) => Promise<Z>; | ||
} | ||
export interface AsyncContract1<A, Z> { | ||
enforce(f: (a: A) => Promise<Z>): (a: A) => Promise<Z>; | ||
} | ||
export interface AsyncContract2<A, B, Z> { | ||
enforce(f: (a: A, b: B) => Promise<Z>): (a: A, b: B) => Promise<Z>; | ||
} | ||
export interface AsyncContract3<A, B, C, Z> { | ||
enforce(f: (a: A, b: B, c: C) => Promise<Z>): (a: A, b: B, c: C) => Promise<Z>; | ||
} | ||
export interface AsyncContract4<A, B, C, D, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D) => Promise<Z>): (a: A, b: B, c: C, d: D) => Promise<Z>; | ||
} | ||
export interface AsyncContract5<A, B, C, D, E, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E) => Promise<Z>; | ||
} | ||
export interface AsyncContract6<A, B, C, D, E, F, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<Z>; | ||
} | ||
export interface AsyncContract7<A, B, C, D, E, F, G, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<Z>; | ||
} | ||
export interface AsyncContract8<A, B, C, D, E, F, G, H, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<Z>; | ||
} | ||
export interface AsyncContract9<A, B, C, D, E, F, G, H, I, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<Z>; | ||
} | ||
export interface AsyncContract10<A, B, C, D, E, F, G, H, I, J, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<Z>): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<Z>; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
export declare function AsyncContract<Z>(Z: Runtype<Z>): AsyncContract0<Z>; | ||
export declare function AsyncContract<A, Z>(A: Runtype<A>, Z: Runtype<Z>): AsyncContract1<A, Z>; | ||
export declare function AsyncContract<A, B, Z>(A: Runtype<A>, B: Runtype<B>, Z: Runtype<Z>): AsyncContract2<A, B, Z>; | ||
export declare function AsyncContract<A, B, C, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, Z: Runtype<Z>): AsyncContract3<A, B, C, Z>; | ||
export declare function AsyncContract<A, B, C, D, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, Z: Runtype<Z>): AsyncContract4<A, B, C, D, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, Z: Runtype<Z>): AsyncContract5<A, B, C, D, E, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, F, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, Z: Runtype<Z>): AsyncContract6<A, B, C, D, E, F, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, F, G, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, Z: Runtype<Z>): AsyncContract7<A, B, C, D, E, F, G, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, F, G, H, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, Z: Runtype<Z>): AsyncContract8<A, B, C, D, E, F, G, H, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, F, G, H, I, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, I: Runtype<I>, Z: Runtype<Z>): AsyncContract9<A, B, C, D, E, F, G, H, I, Z>; | ||
export declare function AsyncContract<A, B, C, D, E, F, G, H, I, J, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, I: Runtype<I>, J: Runtype<J>, Z: Runtype<Z>): AsyncContract10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
export declare function AsyncContract<A extends [any, ...any[]] | [], Z>(argTypes: { | ||
[key in keyof A]: key extends 'length' ? A['length'] : RuntypeBase<A[key]>; | ||
}, returnType: RuntypeBase<Z>): AsyncContract<A, Z>; |
@@ -1,48 +0,10 @@ | ||
import { Runtype } from './index'; | ||
export interface Contract0<Z> { | ||
enforce(f: () => Z): () => Z; | ||
import { RuntypeBase } from './runtype'; | ||
export interface Contract<A extends any[], Z> { | ||
enforce(f: (...a: A) => Z): (...a: A) => Z; | ||
} | ||
export interface Contract1<A, Z> { | ||
enforce(f: (a: A) => Z): (a: A) => Z; | ||
} | ||
export interface Contract2<A, B, Z> { | ||
enforce(f: (a: A, b: B) => Z): (a: A, b: B) => Z; | ||
} | ||
export interface Contract3<A, B, C, Z> { | ||
enforce(f: (a: A, b: B, c: C) => Z): (a: A, b: B, c: C) => Z; | ||
} | ||
export interface Contract4<A, B, C, D, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D) => Z): (a: A, b: B, c: C, d: D) => Z; | ||
} | ||
export interface Contract5<A, B, C, D, E, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E) => Z): (a: A, b: B, c: C, d: D, e: E) => Z; | ||
} | ||
export interface Contract6<A, B, C, D, E, F, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F) => Z): (a: A, b: B, c: C, d: D, e: E, f: F) => Z; | ||
} | ||
export interface Contract7<A, B, C, D, E, F, G, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Z): (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Z; | ||
} | ||
export interface Contract8<A, B, C, D, E, F, G, H, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Z): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Z; | ||
} | ||
export interface Contract9<A, B, C, D, E, F, G, H, I, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Z): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Z; | ||
} | ||
export interface Contract10<A, B, C, D, E, F, G, H, I, J, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Z): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Z; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
export declare function Contract<Z>(Z: Runtype<Z>): Contract0<Z>; | ||
export declare function Contract<A, Z>(A: Runtype<A>, Z: Runtype<Z>): Contract1<A, Z>; | ||
export declare function Contract<A, B, Z>(A: Runtype<A>, B: Runtype<B>, Z: Runtype<Z>): Contract2<A, B, Z>; | ||
export declare function Contract<A, B, C, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, Z: Runtype<Z>): Contract3<A, B, C, Z>; | ||
export declare function Contract<A, B, C, D, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, Z: Runtype<Z>): Contract4<A, B, C, D, Z>; | ||
export declare function Contract<A, B, C, D, E, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, Z: Runtype<Z>): Contract5<A, B, C, D, E, Z>; | ||
export declare function Contract<A, B, C, D, E, F, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, Z: Runtype<Z>): Contract6<A, B, C, D, E, F, Z>; | ||
export declare function Contract<A, B, C, D, E, F, G, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, Z: Runtype<Z>): Contract7<A, B, C, D, E, F, G, Z>; | ||
export declare function Contract<A, B, C, D, E, F, G, H, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, Z: Runtype<Z>): Contract8<A, B, C, D, E, F, G, H, Z>; | ||
export declare function Contract<A, B, C, D, E, F, G, H, I, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, I: Runtype<I>, Z: Runtype<Z>): Contract9<A, B, C, D, E, F, G, H, I, Z>; | ||
export declare function Contract<A, B, C, D, E, F, G, H, I, J, Z>(A: Runtype<A>, B: Runtype<B>, C: Runtype<C>, D: Runtype<D>, E: Runtype<E>, F: Runtype<F>, G: Runtype<G>, H: Runtype<H>, I: Runtype<I>, J: Runtype<J>, Z: Runtype<Z>): Contract10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
export declare function Contract<A extends [any, ...any[]] | [], Z>(argTypes: { | ||
[key in keyof A]: key extends 'length' ? A['length'] : RuntypeBase<A[key]>; | ||
}, returnType: RuntypeBase<Z>): Contract<A, Z>; |
@@ -0,0 +0,0 @@ export declare class ValidationError extends Error { |
@@ -1,27 +0,32 @@ | ||
export { Runtype, Static } from './runtype'; | ||
export * from './reflect'; | ||
export * from './result'; | ||
export * from './contract'; | ||
export * from './asynccontract'; | ||
export * from './match'; | ||
export * from './errors'; | ||
export * from './types/unknown'; | ||
export * from './types/never'; | ||
export * from './types/void'; | ||
export { Literal, Undefined, Null } from './types/literal'; | ||
export * from './types/boolean'; | ||
export * from './types/number'; | ||
export * from './types/string'; | ||
export * from './types/symbol'; | ||
export * from './types/array'; | ||
export * from './types/tuple'; | ||
export * from './types/record'; | ||
export * from './types/dictionary'; | ||
export * from './types/union'; | ||
export * from './types/intersect'; | ||
export * from './types/function'; | ||
export { AsyncContract } from './asynccontract'; | ||
export { Contract } from './contract'; | ||
export { assertType } from './assertType'; | ||
export type { Runtype, Codec, Static } from './runtype'; | ||
export type { Success, Failure, Result } from './result'; | ||
export { ValidationError } from './errors'; | ||
export { Array, ReadonlyArray } from './types/array'; | ||
export { Boolean } from './types/boolean'; | ||
export type { ConstraintCheck } from './types/constraint'; | ||
export { Constraint, Guard } from './types/constraint'; | ||
export { Dictionary } from './types/dictionary'; | ||
export { Function } from './types/function'; | ||
export { InstanceOf } from './types/instanceof'; | ||
export * from './types/lazy'; | ||
export * from './types/constraint'; | ||
export { Intersect } from './types/intersect'; | ||
export { Lazy } from './types/lazy'; | ||
export type { LiteralValue } from './types/literal'; | ||
export { Literal, Null, Undefined } from './types/literal'; | ||
export { Never } from './types/never'; | ||
export { Number } from './types/number'; | ||
export { Object, Partial } from './types/Object'; | ||
export { Record } from './types/Record'; | ||
export { String } from './types/string'; | ||
export { Symbol } from './types/symbol'; | ||
export { Tuple } from './types/tuple'; | ||
export { Union } from './types/union'; | ||
export { Unknown } from './types/unknown'; | ||
/** | ||
* @deprecated use Unknown | ||
*/ | ||
export { Void } from './types/void'; | ||
export { Brand } from './types/brand'; | ||
export * from './decorator'; | ||
export { ParsedValue } from './types/ParsedValue'; |
1154
lib/index.js
@@ -1,34 +0,1122 @@ | ||
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
'use strict'; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
class ValidationError extends Error { | ||
constructor(message, key) { | ||
super(key ? `${message} in ${key}` : message); | ||
this.key = key; | ||
this.name = 'ValidationError'; | ||
Object.setPrototypeOf(this, ValidationError.prototype); | ||
} | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./contract")); | ||
__export(require("./asynccontract")); | ||
__export(require("./match")); | ||
__export(require("./errors")); | ||
__export(require("./types/unknown")); | ||
__export(require("./types/never")); | ||
__export(require("./types/void")); | ||
var literal_1 = require("./types/literal"); | ||
exports.Literal = literal_1.Literal; | ||
exports.Undefined = literal_1.Undefined; | ||
exports.Null = literal_1.Null; | ||
__export(require("./types/boolean")); | ||
__export(require("./types/number")); | ||
__export(require("./types/string")); | ||
__export(require("./types/symbol")); | ||
__export(require("./types/array")); | ||
__export(require("./types/tuple")); | ||
__export(require("./types/record")); | ||
__export(require("./types/dictionary")); | ||
__export(require("./types/union")); | ||
__export(require("./types/intersect")); | ||
__export(require("./types/function")); | ||
var instanceof_1 = require("./types/instanceof"); | ||
exports.InstanceOf = instanceof_1.InstanceOf; | ||
__export(require("./types/lazy")); | ||
__export(require("./types/constraint")); | ||
var brand_1 = require("./types/brand"); | ||
exports.Brand = brand_1.Brand; | ||
__export(require("./decorator")); | ||
function lazyValue(fn) { | ||
let value; | ||
return () => { | ||
if (!value) { | ||
value = fn(); | ||
} | ||
return value; | ||
}; | ||
} | ||
function isLazyRuntype(runtype) { | ||
return 'tag' in runtype && runtype.tag === 'lazy'; | ||
} | ||
/** | ||
* Construct a possibly-recursive Runtype. | ||
*/ | ||
function Lazy(delayed) { | ||
const underlying = lazyValue(delayed); | ||
return create((value, _innerValidate, innerValidateToPlaceholder) => { | ||
return innerValidateToPlaceholder(underlying(), value); | ||
}, { | ||
tag: 'lazy', | ||
underlying, | ||
show({ showChild, needsParens }) { | ||
return showChild(underlying(), needsParens); | ||
}, | ||
}); | ||
} | ||
const show = (needsParens, circular) => (runtype) => { | ||
const parenthesize = (s) => (needsParens ? `(${s})` : s); | ||
const showChild = (runtype, needsParens) => show(needsParens, circular)(runtype); | ||
if (circular.has(runtype)) { | ||
if (isLazyRuntype(runtype)) { | ||
const underlying = runtype.underlying(); | ||
if (underlying !== runtype) { | ||
return show(needsParens, circular)(underlying); | ||
} | ||
} | ||
return parenthesize(`CIRCULAR ${runtype.tag}`); | ||
} | ||
if (runtype.show) { | ||
circular.add(runtype); | ||
try { | ||
return runtype.show({ parenthesize, showChild, needsParens }); | ||
} | ||
finally { | ||
circular.delete(runtype); | ||
} | ||
} | ||
return runtype.tag; | ||
}; | ||
var show$1 = show(false, new Set()); | ||
function isParsedValueRuntype(runtype) { | ||
return 'tag' in runtype && runtype.tag === 'parsed'; | ||
} | ||
function ParsedValue(underlying, config) { | ||
return create({ | ||
validate: (value, _innerValidate, innerValidateToPlaceholder) => { | ||
return mapValidationPlaceholder(innerValidateToPlaceholder(underlying, value), source => { | ||
return config.parse(source); | ||
}, config.test); | ||
}, | ||
test(value, internalTest) { | ||
if (config.test) { | ||
return internalTest(config.test, value); | ||
} | ||
else { | ||
return { | ||
success: false, | ||
message: `${config.name || `ParsedValue<${show$1(underlying)}>`} does not support Runtype.test`, | ||
}; | ||
} | ||
}, | ||
serialize(value, _internalSerialize, _internalSerializeToPlaceholder) { | ||
if (!config.serialize) { | ||
return { | ||
success: false, | ||
message: `${config.name || `ParsedValue<${show$1(underlying)}>`} does not support Runtype.serialize`, | ||
}; | ||
} | ||
const testResult = config.test | ||
? innerGuard(config.test, value, createGuardVisitedState()) | ||
: undefined; | ||
if (testResult) { | ||
return testResult; | ||
} | ||
const serialized = config.serialize(value); | ||
if (!serialized.success) { | ||
return serialized; | ||
} | ||
return _internalSerializeToPlaceholder(underlying, serialized.value); | ||
}, | ||
}, { | ||
tag: 'parsed', | ||
underlying, | ||
config, | ||
show({ showChild }) { | ||
return config.name || `ParsedValue<${showChild(underlying, false)}>`; | ||
}, | ||
}); | ||
} | ||
const internal = '__internal__'; | ||
function create(internalImplementation, config) { | ||
const A = { | ||
...config, | ||
assert, | ||
parse, | ||
check: parse, | ||
safeParse, | ||
validate: safeParse, | ||
test, | ||
guard: test, | ||
serialize, | ||
safeSerialize, | ||
Or, | ||
And, | ||
withConstraint, | ||
withGuard, | ||
withBrand, | ||
withParser, | ||
toString: () => `Runtype<${show$1(A)}>`, | ||
[internal]: typeof internalImplementation === 'function' | ||
? { | ||
validate: internalImplementation, | ||
} | ||
: internalImplementation, | ||
}; | ||
return A; | ||
function safeParse(x) { | ||
return innerValidate(A, x, createVisitedState()); | ||
} | ||
function safeSerialize(x) { | ||
return innerSerialize(A, x, createVisitedState()); | ||
} | ||
function parse(x) { | ||
const validated = safeParse(x); | ||
if (!validated.success) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
return validated.value; | ||
} | ||
function serialize(x) { | ||
const validated = safeSerialize(x); | ||
if (!validated.success) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
return validated.value; | ||
} | ||
function assert(x) { | ||
const validated = innerGuard(A, x, createGuardVisitedState()); | ||
if (validated) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
} | ||
function test(x) { | ||
const validated = innerGuard(A, x, createGuardVisitedState()); | ||
return validated === undefined; | ||
} | ||
function Or(B) { | ||
return Union(A, B); | ||
} | ||
function And(B) { | ||
return Intersect(A, B); | ||
} | ||
function withConstraint(constraint, options) { | ||
return Constraint(A, constraint, options); | ||
} | ||
function withGuard(test, options) { | ||
return Constraint(A, test, options); | ||
} | ||
function withBrand(B) { | ||
return Brand(B, A); | ||
} | ||
function withParser(config) { | ||
return ParsedValue(A, config); | ||
} | ||
} | ||
function attemptMixin(placeholder, value) { | ||
if (placeholder === value) { | ||
return { success: true, value }; | ||
} | ||
if (Array.isArray(placeholder) && Array.isArray(value)) { | ||
placeholder.splice(0, placeholder.length, ...value); | ||
return { success: true, value: placeholder }; | ||
} | ||
if (placeholder && | ||
typeof placeholder === 'object' && | ||
!Array.isArray(placeholder) && | ||
value && | ||
typeof value === 'object' && | ||
!Array.isArray(value)) { | ||
Object.assign(placeholder, value); | ||
return { success: true, value: placeholder }; | ||
} | ||
return { | ||
success: false, | ||
message: `Cannot convert a value of type "${Array.isArray(placeholder) ? 'Array' : typeof placeholder}" into a value of type "${value === null ? 'null' : Array.isArray(value) ? 'Array' : typeof value}" when it contains cycles.`, | ||
}; | ||
} | ||
function createValidationPlaceholder(placeholder, fn) { | ||
return innerMapValidationPlaceholder(placeholder, () => fn(placeholder) || { success: true, value: placeholder }); | ||
} | ||
function mapValidationPlaceholder(source, fn, extraGuard) { | ||
if (!source.success) | ||
return source; | ||
if (!source.cycle) { | ||
const result = fn(source.value); | ||
return ((result.success && | ||
extraGuard && | ||
innerGuard(extraGuard, result.value, createGuardVisitedState())) || | ||
result); | ||
} | ||
return innerMapValidationPlaceholder(Array.isArray(source.placeholder) ? [...source.placeholder] : { ...source.placeholder }, () => source.unwrap(), fn, extraGuard); | ||
} | ||
function innerMapValidationPlaceholder(placeholder, populate, fn, extraGuard) { | ||
let hasCycle = false; | ||
let cache; | ||
const cycle = { | ||
success: true, | ||
cycle: true, | ||
placeholder, | ||
unwrap: () => { | ||
if (cache) { | ||
hasCycle = true; | ||
return cache; | ||
} | ||
cache = { success: true, value: placeholder }; | ||
const sourceResult = populate(); | ||
const result = sourceResult.success && fn ? fn(sourceResult.value) : sourceResult; | ||
if (!result.success) | ||
return result; | ||
if (hasCycle) { | ||
const unwrapResult = attemptMixin(cache.value, result.value); | ||
const guardFailure = unwrapResult.success && | ||
extraGuard && | ||
innerGuard(extraGuard, unwrapResult.value, createGuardVisitedState()); | ||
cache = guardFailure || unwrapResult; | ||
} | ||
else { | ||
const guardFailure = extraGuard && innerGuard(extraGuard, result.value, createGuardVisitedState()); | ||
cache = guardFailure || result; | ||
} | ||
if (cache.success) { | ||
cycle.placeholder = cache.value; | ||
} | ||
return cache; | ||
}, | ||
}; | ||
return cycle; | ||
} | ||
function unwrapVisitedState(o) { | ||
return o; | ||
} | ||
function wrapVisitedState(o) { | ||
return o; | ||
} | ||
function createVisitedState() { | ||
return wrapVisitedState(new Map()); | ||
} | ||
function unwrapGuardVisitedState(o) { | ||
return o; | ||
} | ||
function wrapGuardVisitedState(o) { | ||
return o; | ||
} | ||
function createGuardVisitedState() { | ||
return wrapGuardVisitedState(new Map()); | ||
} | ||
function innerValidate(targetType, value, $visited) { | ||
const result = innerValidateToPlaceholder(targetType, value, $visited); | ||
if (result.cycle) { | ||
return result.unwrap(); | ||
} | ||
return result; | ||
} | ||
function innerValidateToPlaceholder(targetType, value, $visited) { | ||
var _a; | ||
const visited = unwrapVisitedState($visited); | ||
const validator = targetType[internal]; | ||
const cached = (_a = visited.get(targetType)) === null || _a === void 0 ? void 0 : _a.get(value); | ||
if (cached !== undefined) { | ||
return cached; | ||
} | ||
const result = validator.validate(value, (t, v) => innerValidate(t, v, $visited), (t, v) => innerValidateToPlaceholder(t, v, $visited)); | ||
if (result.cycle) { | ||
visited.set(targetType, (visited.get(targetType) || new Map()).set(value, result)); | ||
return result; | ||
} | ||
return result; | ||
} | ||
function innerSerialize(targetType, value, $visited) { | ||
const result = innerSerializeToPlaceholder(targetType, value, $visited); | ||
if (result.cycle) { | ||
return result.unwrap(); | ||
} | ||
return result; | ||
} | ||
function innerSerializeToPlaceholder(targetType, value, $visited) { | ||
var _a; | ||
const visited = unwrapVisitedState($visited); | ||
const validator = targetType[internal]; | ||
const cached = (_a = visited.get(targetType)) === null || _a === void 0 ? void 0 : _a.get(value); | ||
if (cached !== undefined) { | ||
return cached; | ||
} | ||
let result = (validator.serialize || validator.validate)(value, (t, v) => innerSerialize(t, v, $visited), (t, v) => innerSerializeToPlaceholder(t, v, $visited)); | ||
if (result.cycle) { | ||
visited.set(targetType, (visited.get(targetType) || new Map()).set(value, result)); | ||
return result; | ||
} | ||
return result; | ||
} | ||
function innerGuard(targetType, value, $visited) { | ||
var _a; | ||
const visited = unwrapGuardVisitedState($visited); | ||
const validator = targetType[internal]; | ||
if (value && (typeof value === 'object' || typeof value === 'function')) { | ||
const cached = (_a = visited.get(targetType)) === null || _a === void 0 ? void 0 : _a.has(value); | ||
if (cached) | ||
return undefined; | ||
visited.set(targetType, (visited.get(targetType) || new Set()).add(value)); | ||
} | ||
if (validator.test) { | ||
return validator.test(value, (t, v) => innerGuard(t, v, $visited)); | ||
} | ||
let result = validator.validate(value, (t, v) => innerGuard(t, v, $visited) || { success: true, value: v }, (t, v) => innerGuard(t, v, $visited) || { success: true, value: v }); | ||
if (result.cycle) | ||
result = result.unwrap(); | ||
if (result.success) | ||
return undefined; | ||
else | ||
return result; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
function AsyncContract(argTypes, returnType) { | ||
return { | ||
enforce: (f) => (...args) => { | ||
if (args.length < argTypes.length) { | ||
return Promise.reject(new ValidationError(`Expected ${argTypes.length} arguments but only received ${args.length}`)); | ||
} | ||
const visited = createVisitedState(); | ||
for (let i = 0; i < argTypes.length; i++) { | ||
const result = innerValidate(argTypes[i], args[i], visited); | ||
if (result.success) { | ||
args[i] = result.value; | ||
} | ||
else { | ||
return Promise.reject(new ValidationError(result.message, result.key)); | ||
} | ||
} | ||
const returnedPromise = f(...args); | ||
if (!(returnedPromise instanceof Promise)) { | ||
return Promise.reject(new ValidationError(`Expected function to return a promise, but instead got ${returnedPromise}`)); | ||
} | ||
return returnedPromise.then(value => { | ||
const result = innerGuard(returnType, value, createGuardVisitedState()); | ||
if (result) { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
return value; | ||
}); | ||
}, | ||
}; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
function Contract(argTypes, returnType) { | ||
return { | ||
enforce: (f) => (...args) => { | ||
if (args.length < argTypes.length) | ||
throw new ValidationError(`Expected ${argTypes.length} arguments but only received ${args.length}`); | ||
const visited = createVisitedState(); | ||
for (let i = 0; i < argTypes.length; i++) { | ||
const result = innerValidate(argTypes[i], args[i], visited); | ||
if (result.success) { | ||
args[i] = result.value; | ||
} | ||
else { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
} | ||
const rawResult = f(...args); | ||
const result = innerGuard(returnType, rawResult, createGuardVisitedState()); | ||
if (result) { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
return rawResult; | ||
}, | ||
}; | ||
} | ||
function assertType(rt, v) { | ||
rt.assert(v); | ||
} | ||
/** | ||
* Construct an array runtype from a runtype for its elements. | ||
*/ | ||
function InternalArr(element, isReadonly) { | ||
const result = create((xs, innerValidate) => { | ||
if (!Array.isArray(xs)) { | ||
return { | ||
success: false, | ||
message: `Expected array, but was ${xs === null ? xs : typeof xs}`, | ||
}; | ||
} | ||
return createValidationPlaceholder([...xs], placeholder => { | ||
for (let i = 0; i < xs.length; i++) { | ||
const validated = innerValidate(element, xs[i]); | ||
if (!validated.success) { | ||
return { | ||
success: false, | ||
message: validated.message, | ||
key: validated.key ? `[${i}].${validated.key}` : `[${i}]`, | ||
}; | ||
} | ||
else { | ||
placeholder[i] = validated.value; | ||
} | ||
} | ||
}); | ||
}, { | ||
tag: 'array', | ||
isReadonly, | ||
element, | ||
show({ showChild }) { | ||
return `${isReadonly ? 'readonly ' : ''}${showChild(element, true)}[]`; | ||
}, | ||
}); | ||
if (!isReadonly) { | ||
result.asReadonly = asReadonly; | ||
} | ||
return result; | ||
function asReadonly() { | ||
return InternalArr(element, true); | ||
} | ||
} | ||
function Arr(element) { | ||
return InternalArr(element, false); | ||
} | ||
function ReadonlyArray(element) { | ||
return InternalArr(element, true); | ||
} | ||
/** | ||
* Validates that a value is a boolean. | ||
*/ | ||
const Boolean = create(value => typeof value === 'boolean' | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected boolean, but was ${value === null ? value : typeof value}`, | ||
}, { tag: 'boolean' }); | ||
/** | ||
* Validates that a value is a string. | ||
*/ | ||
const String$1 = create(value => typeof value === 'string' | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected string, but was ${value === null ? value : typeof value}`, | ||
}, { tag: 'string' }); | ||
/** | ||
* Validates anything, but provides no new type information about it. | ||
*/ | ||
const Unknown = create(value => ({ success: true, value }), { | ||
tag: 'unknown', | ||
}); | ||
function isConstraintRuntype(runtype) { | ||
return ('tag' in runtype && runtype.tag === 'constraint'); | ||
} | ||
function Constraint(underlying, constraint, options) { | ||
return create((value, innerValidate) => { | ||
const name = options && options.name; | ||
const validated = innerValidate(underlying, value); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
const result = constraint(validated.value); | ||
if (String$1.test(result)) | ||
return { success: false, message: result }; | ||
else if (!result) | ||
return { success: false, message: `Failed ${name || 'constraint'} check` }; | ||
return { success: true, value: validated.value }; | ||
}, { | ||
tag: 'constraint', | ||
underlying, | ||
constraint, | ||
name: options && options.name, | ||
args: options && options.args, | ||
show({ needsParens, showChild }) { | ||
return (options && options.name) || showChild(underlying, needsParens); | ||
}, | ||
}); | ||
} | ||
const Guard = (test, options) => Unknown.withGuard(test, options); | ||
function Dictionary(value, key = 'string') { | ||
return Record(key === 'number' ? Number : String$1, value); | ||
} | ||
/** | ||
* Construct a runtype for functions. | ||
*/ | ||
const Function = create(value => typeof value === 'function' | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected function, but was ${value === null ? value : typeof value}`, | ||
}, { tag: 'function' }); | ||
function InstanceOf(ctor) { | ||
return create(value => value instanceof ctor | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected ${ctor.name}, but was ${value === null ? value : typeof value}`, | ||
}, { | ||
tag: 'instanceof', | ||
ctor: ctor, | ||
show() { | ||
const name = ctor.name; | ||
return `InstanceOf<${name}>`; | ||
}, | ||
}); | ||
} | ||
/** | ||
* Construct an intersection runtype from runtypes for its alternatives. | ||
*/ | ||
function Intersect(...intersectees) { | ||
return create((value, innerValidate) => { | ||
if (Array.isArray(value)) { | ||
return createValidationPlaceholder([...value], placeholder => { | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, placeholder); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
if (!Array.isArray(validated.value)) { | ||
return { | ||
success: false, | ||
message: `The validator ${show$1(targetType)} attempted to convert the type of this value from an array to something else. That conversion is not valid as the child of an intersect`, | ||
}; | ||
} | ||
placeholder.splice(0, placeholder.length, ...validated.value); | ||
} | ||
}); | ||
} | ||
else if (value && typeof value === 'object') { | ||
return createValidationPlaceholder({}, placeholder => { | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, value); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
if (!(validated.value && typeof validated.value === 'object')) { | ||
return { | ||
success: false, | ||
message: `The validator ${show$1(targetType)} attempted to convert the type of this value from an object to something else. That conversion is not valid as the child of an intersect`, | ||
}; | ||
} | ||
Object.assign(placeholder, validated.value); | ||
} | ||
}); | ||
} | ||
let result = value; | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, result); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
result = validated.value; | ||
} | ||
return { success: true, value: result }; | ||
}, { | ||
tag: 'intersect', | ||
intersectees, | ||
show({ parenthesize, showChild }) { | ||
return parenthesize(`${intersectees.map(v => showChild(v, true)).join(' & ')}`); | ||
}, | ||
}); | ||
} | ||
/** | ||
* Be aware of an Array of Symbols `[Symbol()]` which would throw "TypeError: Cannot convert a Symbol value to a string" | ||
*/ | ||
function literal(value) { | ||
return Array.isArray(value) ? String(value.map(String)) : String(value); | ||
} | ||
function isLiteralRuntype(runtype) { | ||
return 'tag' in runtype && runtype.tag === 'literal'; | ||
} | ||
/** | ||
* Construct a runtype for a type literal. | ||
*/ | ||
function Literal(valueBase) { | ||
return create(value => value === valueBase | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected literal '${literal(valueBase)}', but was '${literal(value)}'`, | ||
}, { | ||
tag: 'literal', | ||
value: valueBase, | ||
show() { | ||
return typeof valueBase === 'string' ? `"${valueBase}"` : String(valueBase); | ||
}, | ||
}); | ||
} | ||
/** | ||
* An alias for Literal(undefined). | ||
*/ | ||
const Undefined = Literal(undefined); | ||
/** | ||
* An alias for Literal(null). | ||
*/ | ||
const Null = Literal(null); | ||
/** | ||
* Validates nothing (unknown fails). | ||
*/ | ||
const Never = create(value => ({ | ||
success: false, | ||
message: `Expected nothing, but was ${value === null ? value : typeof value}`, | ||
}), { tag: 'never' }); | ||
/** | ||
* Validates that a value is a number. | ||
*/ | ||
const Number = create(value => typeof value === 'number' | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected number, but was ${value === null ? value : typeof value}`, | ||
}, { tag: 'number' }); | ||
// Type test to determine if an object has a given key | ||
// If this feature gets implemented, we can use `in` instead: https://github.com/Microsoft/TypeScript/issues/10485 | ||
function hasKey(k, o) { | ||
return typeof o === 'object' && k in o; | ||
} | ||
function isObjectRuntype(runtype) { | ||
return ('tag' in runtype && runtype.tag === 'object'); | ||
} | ||
/** | ||
* Construct an object runtype from runtypes for its values. | ||
*/ | ||
function InternalObject(fields, isPartial, isReadonly) { | ||
const runtype = create((x, innerValidate) => { | ||
if (x === null || x === undefined) { | ||
return { success: false, message: `Expected ${show$1(runtype)}, but was ${x}` }; | ||
} | ||
if (typeof x !== 'object') { | ||
return { success: false, message: `Expected ${show$1(runtype)}, but was ${typeof x}` }; | ||
} | ||
if (Array.isArray(x)) { | ||
return { success: false, message: `Expected ${show$1(runtype)}, but was an Array` }; | ||
} | ||
return createValidationPlaceholder({}, (placeholder) => { | ||
for (const key in fields) { | ||
if (!isPartial || (hasKey(key, x) && x[key] !== undefined)) { | ||
const value = isPartial || hasKey(key, x) ? x[key] : undefined; | ||
let validated = innerValidate(fields[key], value); | ||
if (!validated.success) { | ||
return { | ||
success: false, | ||
message: validated.message, | ||
key: validated.key ? `${key}.${validated.key}` : key, | ||
}; | ||
} | ||
placeholder[key] = validated.value; | ||
} | ||
} | ||
}); | ||
}, { | ||
tag: 'object', | ||
isPartial, | ||
isReadonly, | ||
fields, | ||
asPartial, | ||
asReadonly, | ||
pick, | ||
omit, | ||
show({ showChild }) { | ||
const keys = Object.keys(fields); | ||
return keys.length | ||
? `{ ${keys | ||
.map(k => `${isReadonly ? 'readonly ' : ''}${k}${isPartial ? '?' : ''}: ${showChild(fields[k], false)};`) | ||
.join(' ')} }` | ||
: '{}'; | ||
}, | ||
}); | ||
return runtype; | ||
function asPartial() { | ||
return InternalObject(runtype.fields, true, runtype.isReadonly); | ||
} | ||
function asReadonly() { | ||
return InternalObject(runtype.fields, runtype.isPartial, true); | ||
} | ||
function pick(...keys) { | ||
const newFields = {}; | ||
for (const key of keys) { | ||
newFields[key] = fields[key]; | ||
} | ||
return InternalObject(newFields, isPartial, isReadonly); | ||
} | ||
function omit(...keys) { | ||
const newFields = { ...fields }; | ||
for (const key of keys) { | ||
if (key in newFields) | ||
delete newFields[key]; | ||
} | ||
return InternalObject(newFields, isPartial, isReadonly); | ||
} | ||
} | ||
function Obj(fields) { | ||
return InternalObject(fields, false, false); | ||
} | ||
function Partial(fields) { | ||
return InternalObject(fields, true, false); | ||
} | ||
function getExpectedBaseType(key) { | ||
switch (key.tag) { | ||
case 'string': | ||
return 'string'; | ||
case 'number': | ||
return 'number'; | ||
case 'literal': | ||
return typeof key.value; | ||
case 'union': | ||
const baseTypes = key.alternatives.map(getExpectedBaseType); | ||
return baseTypes.reduce((a, b) => (a === b ? a : 'mixed'), baseTypes[0]); | ||
case 'constraint': | ||
return getExpectedBaseType(key.underlying); | ||
} | ||
} | ||
function Record(...args) { | ||
if (args.length === 1 && args[0] && typeof args[0] === 'object') { | ||
return Obj(args[0]); | ||
} | ||
return RecordInternal(args[0], args[1]); | ||
} | ||
function RecordInternal(key, value) { | ||
const expectedBaseType = lazyValue(() => getExpectedBaseType(key)); | ||
const runtype = create((x, innerValidate) => { | ||
if (x === null || x === undefined) { | ||
return { success: false, message: `Expected ${show$1(runtype)}, but was ${x}` }; | ||
} | ||
if (typeof x !== 'object') { | ||
return { success: false, message: `Expected ${show$1(runtype)}, but was ${typeof x}` }; | ||
} | ||
if (Object.getPrototypeOf(x) !== Object.prototype) { | ||
if (!Array.isArray(x)) { | ||
return { | ||
success: false, | ||
message: `Expected ${show$1(runtype)}, but was ${Object.getPrototypeOf(x)}`, | ||
}; | ||
} | ||
return { success: false, message: 'Expected record, but was array' }; | ||
} | ||
return createValidationPlaceholder({}, placeholder => { | ||
for (const k in x) { | ||
let keyValidation = null; | ||
if (expectedBaseType() === 'number') { | ||
if (isNaN(+k)) | ||
return { | ||
success: false, | ||
message: `Expected record key to be a number, but was '${k}'`, | ||
}; | ||
keyValidation = innerValidate(key, +k); | ||
} | ||
else if (expectedBaseType() === 'string') { | ||
keyValidation = innerValidate(key, k); | ||
} | ||
else { | ||
keyValidation = innerValidate(key, k); | ||
if (!keyValidation.success && !isNaN(+k)) { | ||
keyValidation = innerValidate(key, +k); | ||
} | ||
} | ||
if (!keyValidation.success) { | ||
return { | ||
success: false, | ||
message: `Expected record key to be ${show$1(key)}, but was '${k}'`, | ||
}; | ||
} | ||
const validated = innerValidate(value, x[k]); | ||
if (!validated.success) { | ||
return { | ||
success: false, | ||
message: validated.message, | ||
key: validated.key ? `${k}.${validated.key}` : k, | ||
}; | ||
} | ||
placeholder[keyValidation.value] = validated.value; | ||
} | ||
}); | ||
}, { | ||
tag: 'record', | ||
key, | ||
value, | ||
show({ showChild }) { | ||
return `{ [_: ${showChild(key, false)}]: ${showChild(value, false)} }`; | ||
}, | ||
}); | ||
return runtype; | ||
} | ||
/** | ||
* Validates that a value is a symbol. | ||
*/ | ||
const Sym = create(value => typeof value === 'symbol' | ||
? { success: true, value } | ||
: { | ||
success: false, | ||
message: `Expected symbol, but was ${value === null ? value : typeof value}`, | ||
}, { tag: 'symbol' }); | ||
function isTupleRuntype(runtype) { | ||
return 'tag' in runtype && runtype.tag === 'tuple'; | ||
} | ||
/** | ||
* Construct a tuple runtype from runtypes for each of its elements. | ||
*/ | ||
function Tuple(...components) { | ||
return create((x, innerValidate) => { | ||
const validated = innerValidate(Arr(Unknown), x); | ||
if (!validated.success) { | ||
return { | ||
success: false, | ||
message: `Expected tuple to be an array: ${validated.message}`, | ||
key: validated.key, | ||
}; | ||
} | ||
if (validated.value.length !== components.length) { | ||
return { | ||
success: false, | ||
message: `Expected an array of length ${components.length}, but was ${validated.value.length}`, | ||
}; | ||
} | ||
return createValidationPlaceholder(validated.value, placeholder => { | ||
for (let i = 0; i < components.length; i++) { | ||
let validatedComponent = innerValidate(components[i], validated.value[i]); | ||
if (!validatedComponent.success) { | ||
return { | ||
success: false, | ||
message: validatedComponent.message, | ||
key: validatedComponent.key ? `[${i}].${validatedComponent.key}` : `[${i}]`, | ||
}; | ||
} | ||
placeholder[i] = validatedComponent.value; | ||
} | ||
}); | ||
}, { | ||
tag: 'tuple', | ||
components, | ||
show({ showChild }) { | ||
return `[${components | ||
.map(e => showChild(e, false)) | ||
.join(', ')}]`; | ||
}, | ||
}); | ||
} | ||
function isBrandRuntype(runtype) { | ||
return 'tag' in runtype && runtype.tag === 'brand'; | ||
} | ||
function Brand(brand, entity) { | ||
return create((value, _innerValidate, innerValidateToPlaceholder) => { | ||
return innerValidateToPlaceholder(entity, value); | ||
}, { | ||
tag: 'brand', | ||
brand, | ||
entity, | ||
show({ showChild, needsParens }) { | ||
return showChild(entity, needsParens); | ||
}, | ||
}); | ||
} | ||
function valueToString(value) { | ||
return value === null || typeof value === 'number' || typeof value === 'boolean' | ||
? value | ||
: typeof value === 'string' | ||
? `'${value}'` | ||
: typeof value; | ||
} | ||
function resolveUnderlyingType(runtype, mode) { | ||
if (isLazyRuntype(runtype)) | ||
return resolveUnderlyingType(runtype.underlying(), mode); | ||
if (isBrandRuntype(runtype)) | ||
return resolveUnderlyingType(runtype.entity, mode); | ||
if (isConstraintRuntype(runtype)) | ||
return resolveUnderlyingType(runtype.underlying, mode); | ||
if (mode === 'p' && isParsedValueRuntype(runtype)) | ||
return resolveUnderlyingType(runtype.underlying, mode); | ||
if (mode === 't' && isParsedValueRuntype(runtype)) { | ||
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : Never; | ||
} | ||
if (mode === 's' && isParsedValueRuntype(runtype)) { | ||
if (!runtype.config.serialize) { | ||
// this node can never match | ||
return Never; | ||
} | ||
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : runtype; | ||
} | ||
return runtype; | ||
} | ||
/** | ||
* Construct a union runtype from runtypes for its alternatives. | ||
*/ | ||
function Union(...alternatives) { | ||
function validateWithKey(tag, types) { | ||
return (value, innerValidate) => { | ||
if (!value || typeof value !== 'object') { | ||
return { | ||
success: false, | ||
message: `Expected ${show$1(runtype)}, but was ${value === null ? value : typeof value}`, | ||
}; | ||
} | ||
const validator = types.get(value[tag]); | ||
if (validator) { | ||
const result = innerValidate(validator, value); | ||
if (!result.success) { | ||
return { | ||
success: false, | ||
message: result.message, | ||
key: `<${tag === 0 ? `[0]` : tag}: ${valueToString(value[tag])}>${result.key ? `.${result.key}` : ``}`, | ||
}; | ||
} | ||
return result; | ||
} | ||
else { | ||
return { | ||
success: false, | ||
message: `Expected ${Array.from(types.keys()) | ||
.map(v => (typeof v === 'string' ? `'${v}'` : v)) | ||
.join(' | ')}, but was ${valueToString(value[tag])}`, | ||
key: tag === 0 ? `[0]` : tag, | ||
}; | ||
} | ||
}; | ||
} | ||
// This must be lazy to avoid eagerly evaluating any circular references | ||
const validatorOf = (mode) => { | ||
const excludingNever = alternatives.filter(t => resolveUnderlyingType(t, mode).tag !== 'never'); | ||
if (excludingNever.length) { | ||
const alts = excludingNever.map(t => resolveUnderlyingType(t, mode)); | ||
const recordAlternatives = alts.filter(isObjectRuntype); | ||
if (recordAlternatives.length === excludingNever.length) { | ||
const commonLiteralFields = {}; | ||
for (let i = 0; i < excludingNever.length; i++) { | ||
for (const fieldName in recordAlternatives[i].fields) { | ||
const field = resolveUnderlyingType(recordAlternatives[i].fields[fieldName], mode); | ||
if (isLiteralRuntype(field)) { | ||
if (!commonLiteralFields[fieldName]) { | ||
commonLiteralFields[fieldName] = new Map(); | ||
} | ||
if (!commonLiteralFields[fieldName].has(field.value)) { | ||
commonLiteralFields[fieldName].set(field.value, | ||
// @ts-expect-error | ||
excludingNever[i]); | ||
} | ||
} | ||
} | ||
} | ||
for (const tag of ['type', 'kind', 'tag', ...Object.keys(commonLiteralFields)]) { | ||
if (tag in commonLiteralFields && | ||
commonLiteralFields[tag].size === excludingNever.length) { | ||
return validateWithKey(tag, commonLiteralFields[tag]); | ||
} | ||
} | ||
} | ||
const tupleAlternatives = alts.filter(isTupleRuntype); | ||
if (tupleAlternatives.length === excludingNever.length) { | ||
const commonLiteralFields = new Map(); | ||
for (let i = 0; i < excludingNever.length; i++) { | ||
const field = resolveUnderlyingType(tupleAlternatives[i].components[0], mode); | ||
if (isLiteralRuntype(field)) { | ||
if (!commonLiteralFields.has(field.value)) { | ||
commonLiteralFields.set(field.value, | ||
// @ts-expect-error | ||
excludingNever[i]); | ||
} | ||
} | ||
} | ||
if (commonLiteralFields.size === excludingNever.length) { | ||
return validateWithKey(0, commonLiteralFields); | ||
} | ||
} | ||
} | ||
return (value, innerValidate) => { | ||
let errorsWithKey = 0; | ||
let lastError; | ||
let lastErrorRuntype; | ||
for (const targetType of alternatives) { | ||
const result = innerValidate(targetType, value); | ||
if (result.success) { | ||
return result; | ||
} | ||
if (result.key) { | ||
errorsWithKey++; | ||
lastError = result; | ||
lastErrorRuntype = targetType; | ||
} | ||
} | ||
if (lastError && lastErrorRuntype && errorsWithKey === 1) { | ||
return { | ||
success: false, | ||
message: lastError.message, | ||
key: `<${show$1(lastErrorRuntype)}>.${lastError.key}`, | ||
}; | ||
} | ||
return { | ||
success: false, | ||
message: `Expected ${show$1(runtype)}, but was ${value === null ? value : typeof value}`, | ||
}; | ||
}; | ||
}; | ||
const innerValidator = lazyValue(() => ({ | ||
p: validatorOf('p'), | ||
s: validatorOf('s'), | ||
t: validatorOf('t'), | ||
})); | ||
const runtype = create({ | ||
validate: (value, visited) => { | ||
return innerValidator().p(value, visited); | ||
}, | ||
serialize: (value, visited) => { | ||
return innerValidator().s(value, visited); | ||
}, | ||
test: (value, visited) => { | ||
const result = innerValidator().s(value, (t, v) => visited(t, v) || { success: true, value: v }); | ||
return result.success ? undefined : result; | ||
}, | ||
}, { | ||
tag: 'union', | ||
alternatives, | ||
match: match, | ||
show({ parenthesize, showChild }) { | ||
return parenthesize(`${alternatives.map(v => showChild(v, true)).join(' | ')}`); | ||
}, | ||
}); | ||
return runtype; | ||
function match(...cases) { | ||
return (x) => { | ||
const visited = createVisitedState(); | ||
for (let i = 0; i < alternatives.length; i++) { | ||
const input = innerValidate(alternatives[i], x, visited); | ||
if (input.success) { | ||
return cases[i](input.value); | ||
} | ||
} | ||
// if none of the types matched, we should fail with an assertion error | ||
runtype.assert(x); | ||
}; | ||
} | ||
} | ||
/** | ||
* Void is an alias for Unknown | ||
* | ||
* @deprecated Please use Unknown instead | ||
*/ | ||
const Void = Unknown; | ||
exports.Array = Arr; | ||
exports.AsyncContract = AsyncContract; | ||
exports.Boolean = Boolean; | ||
exports.Brand = Brand; | ||
exports.Constraint = Constraint; | ||
exports.Contract = Contract; | ||
exports.Dictionary = Dictionary; | ||
exports.Function = Function; | ||
exports.Guard = Guard; | ||
exports.InstanceOf = InstanceOf; | ||
exports.Intersect = Intersect; | ||
exports.Lazy = Lazy; | ||
exports.Literal = Literal; | ||
exports.Never = Never; | ||
exports.Null = Null; | ||
exports.Number = Number; | ||
exports.Object = Obj; | ||
exports.ParsedValue = ParsedValue; | ||
exports.Partial = Partial; | ||
exports.ReadonlyArray = ReadonlyArray; | ||
exports.Record = Record; | ||
exports.String = String$1; | ||
exports.Symbol = Sym; | ||
exports.Tuple = Tuple; | ||
exports.Undefined = Undefined; | ||
exports.Union = Union; | ||
exports.Unknown = Unknown; | ||
exports.ValidationError = ValidationError; | ||
exports.Void = Void; | ||
exports.assertType = assertType; |
@@ -0,0 +0,0 @@ /** |
@@ -1,34 +0,79 @@ | ||
import { Result, Union2, Intersect2, Constraint, ConstraintCheck, Brand } from './index'; | ||
import { Reflect } from './reflect'; | ||
import { Result, Union, Intersect, Constraint, ConstraintCheck, Brand, Failure } from './index'; | ||
import { ParsedValue, ParsedValueConfig } from './types/ParsedValue'; | ||
export declare type InnerValidateHelper = <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>; | ||
declare const internalSymbol: unique symbol; | ||
declare const internal: typeof internalSymbol; | ||
export declare type ResultWithCycle<T> = (Result<T> & { | ||
cycle?: false; | ||
}) | Cycle<T>; | ||
export interface InternalValidation<TParsed> { | ||
validate(x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>, innerValidateToPlaceholder: <T>(runtype: RuntypeBase<T>, value: unknown) => ResultWithCycle<T>): ResultWithCycle<TParsed>; | ||
test?: (x: any, innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Failure | undefined) => Failure | undefined; | ||
serialize?: (x: any, innerSerialize: (runtype: RuntypeBase, value: unknown) => Result<any>, innerSerializeToPlaceholder: (runtype: RuntypeBase, value: unknown) => ResultWithCycle<any>) => ResultWithCycle<any>; | ||
} | ||
/** | ||
* A runtype determines at runtime whether a value conforms to a type specification. | ||
*/ | ||
export interface Runtype<A = unknown> { | ||
export interface RuntypeBase<TParsed = unknown> { | ||
readonly tag: string; | ||
/** | ||
* Verifies that a value conforms to this runtype. When given a value that does | ||
* not conform to the runtype, throws an exception. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
assert(x: any): asserts x is A; | ||
assert(x: any): asserts x is TParsed; | ||
/** | ||
* Verifies that a value conforms to this runtype. If so, returns the same value, | ||
* statically typed. Otherwise throws an exception. | ||
* A type guard for this runtype. | ||
*/ | ||
check(x: any): A; | ||
test(x: any): x is TParsed; | ||
/** | ||
* Validates that a value conforms to this type, and returns a result indicating | ||
* success or failure (does not throw). | ||
* @deprecated use Runtype.test | ||
*/ | ||
validate(x: any): Result<A>; | ||
guard(x: any): x is TParsed; | ||
/** | ||
* A type guard for this runtype. | ||
* Validates the value conforms to this type, and performs | ||
* the `parse` action for any `ParsedValue` types. | ||
* | ||
* If the value is valid, it returns the parsed value, | ||
* otherwise it throws a ValidationError. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
guard(x: any): x is A; | ||
parse(x: any): TParsed; | ||
/** | ||
* @deprecated use Runtype.parse | ||
*/ | ||
check(x: any): TParsed; | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `parse` action for any `ParsedValue` types. | ||
* | ||
* Returns a `Result`, constaining the parsed value or | ||
* error message. Does not throw! | ||
*/ | ||
safeParse(x: any): Result<TParsed>; | ||
/** | ||
* @deprecated use Runtype.safeParse | ||
*/ | ||
validate(x: any): Result<TParsed>; | ||
show?: (ctx: { | ||
needsParens: boolean; | ||
parenthesize: (str: string) => string; | ||
showChild: (rt: RuntypeBase, needsParens: boolean) => string; | ||
}) => string; | ||
[internal]: InternalValidation<TParsed>; | ||
} | ||
/** | ||
* A runtype determines at runtime whether a value conforms to a type specification. | ||
*/ | ||
export interface Runtype<TParsed> extends RuntypeBase<TParsed> { | ||
/** | ||
* Union this Runtype with another. | ||
*/ | ||
Or<B extends Runtype>(B: B): Union2<this, B>; | ||
Or<B extends RuntypeBase>(B: B): Union<[this, B]>; | ||
/** | ||
* Intersect this Runtype with another. | ||
*/ | ||
And<B extends Runtype>(B: B): Intersect2<this, B>; | ||
And<B extends RuntypeBase>(B: B): Intersect<[this, B]>; | ||
/** | ||
@@ -54,7 +99,7 @@ * Use an arbitrary constraint function to validate a runtype, and optionally | ||
* via a type guard function. The static type of the runtype is inferred from | ||
* the type of the guard function. | ||
* the type of the test function. | ||
* | ||
* @template T - Typically inferred from the return type of the type guard | ||
* function, so usually not needed to specify manually. | ||
* @param {(x: Static<this>) => x is T} guard - Type guard function (see | ||
* @param {(x: Static<this>) => x is T} test - Type test function (see | ||
* https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) | ||
@@ -67,3 +112,3 @@ * | ||
*/ | ||
withGuard<T extends Static<this>, K = unknown>(guard: (x: Static<this>) => x is T, options?: { | ||
withGuard<T extends Static<this>, K = unknown>(test: (x: Static<this>) => x is T, options?: { | ||
name?: string; | ||
@@ -77,17 +122,49 @@ args?: K; | ||
/** | ||
* Convert this to a Reflect, capable of introspecting the structure of the type. | ||
* Apply conversion functions when parsing/serializing this value | ||
*/ | ||
reflect: Reflect; | ||
_falseWitness: A; | ||
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): ParsedValue<this, TParsed>; | ||
} | ||
export interface Codec<TParsed> extends Runtype<TParsed> { | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `serialize` action for any `ParsedValue` types. | ||
* | ||
* If the value is valid, and the type supports serialize, | ||
* it returns the serialized value, otherwise it throws a | ||
* ValidationError. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
serialize: (x: TParsed) => unknown; | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `serialize` action for any `ParsedValue` types. | ||
* | ||
* Returns a `Result`, constaining the serialized value or | ||
* error message. Does not throw! | ||
*/ | ||
safeSerialize: (x: TParsed) => Result<unknown>; | ||
} | ||
/** | ||
* Obtains the static type associated with a Runtype. | ||
*/ | ||
export declare type Static<A extends Runtype> = A['_falseWitness']; | ||
export declare function create<A extends Runtype>(validate: (x: any, visited: VisitedState) => Result<Static<A>>, A: any): A; | ||
export declare function innerValidate<A extends Runtype>(targetType: A, value: any, visited: VisitedState): Result<Static<A>>; | ||
declare type VisitedState = { | ||
has: (candidate: object, type: Runtype) => boolean; | ||
export declare type Static<A extends RuntypeBase<any>> = A extends RuntypeBase<infer T> ? T : unknown; | ||
export declare function create<TConfig extends Codec<any>>(internalImplementation: InternalValidation<Static<TConfig>> | InternalValidation<Static<TConfig>>['validate'], config: Omit<TConfig, 'assert' | 'check' | 'test' | 'guard' | 'parse' | 'check' | 'safeParse' | 'validate' | 'serialize' | 'safeSerialize' | 'Or' | 'And' | 'withConstraint' | 'withGuard' | 'withBrand' | 'withParser' | typeof internal>): TConfig; | ||
export declare type Cycle<T> = { | ||
success: true; | ||
cycle: true; | ||
placeholder: Partial<T>; | ||
unwrap: () => Result<T>; | ||
}; | ||
declare function VisitedState(): VisitedState; | ||
export declare function createValidationPlaceholder<T>(placeholder: T, fn: (placeholder: T) => Failure | undefined): Cycle<T>; | ||
export declare function mapValidationPlaceholder<T, S>(source: ResultWithCycle<T>, fn: (placeholder: T) => Result<S>, extraGuard?: RuntypeBase<S>): ResultWithCycle<S>; | ||
declare const OpaqueVisitedState: unique symbol; | ||
export declare type OpaqueVisitedState = typeof OpaqueVisitedState; | ||
export declare function createVisitedState(): OpaqueVisitedState; | ||
declare const OpaqueGuardVisitedState: unique symbol; | ||
export declare type OpaqueGuardVisitedState = typeof OpaqueGuardVisitedState; | ||
export declare function createGuardVisitedState(): OpaqueGuardVisitedState; | ||
export declare function innerValidate<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState): Result<T>; | ||
export declare function innerSerialize<T>(targetType: RuntypeBase<T>, value: any, $visited: OpaqueVisitedState): Result<T>; | ||
export declare function innerGuard(targetType: RuntypeBase, value: any, $visited: OpaqueGuardVisitedState): Failure | undefined; | ||
export {}; |
@@ -1,3 +0,3 @@ | ||
import { Reflect } from './index'; | ||
declare const _default: (refl: Reflect) => string; | ||
import { RuntypeBase } from './runtype'; | ||
declare const _default: (runtype: RuntypeBase<unknown>) => string; | ||
export default _default; |
@@ -1,10 +0,15 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
declare type ArrayStaticType<E extends Runtype, RO extends boolean> = RO extends true ? ReadonlyArray<Static<E>> : Static<E>[]; | ||
interface Arr<E extends Runtype, RO extends boolean> extends Runtype<ArrayStaticType<E, RO>> { | ||
tag: 'array'; | ||
element: E; | ||
isReadonly: RO; | ||
asReadonly(): Arr<E, true>; | ||
import { Static, RuntypeBase, Codec } from '../runtype'; | ||
export interface ReadonlyArray<E extends RuntypeBase<unknown> = RuntypeBase<unknown>> extends Codec<readonly Static<E>[]> { | ||
readonly tag: 'array'; | ||
readonly element: E; | ||
readonly isReadonly: true; | ||
} | ||
declare function Arr<E extends Runtype, RO extends boolean>(element: E): Arr<E, false>; | ||
export { Arr as Array }; | ||
interface Arr<E extends RuntypeBase<unknown> = RuntypeBase<unknown>> extends Codec<Static<E>[]> { | ||
readonly tag: 'array'; | ||
readonly element: E; | ||
readonly isReadonly: false; | ||
asReadonly(): ReadonlyArray<E>; | ||
} | ||
declare function Arr<TElement extends RuntypeBase<unknown>>(element: TElement): Arr<TElement>; | ||
export declare function ReadonlyArray<TElement extends RuntypeBase<unknown>>(element: TElement): ReadonlyArray<TElement>; |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface Boolean extends Runtype<boolean> { | ||
tag: 'boolean'; | ||
import { Codec } from '../runtype'; | ||
export interface Boolean extends Codec<boolean> { | ||
readonly tag: 'boolean'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,10 +0,11 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
import { RuntypeBase, Static, Codec } from '../runtype'; | ||
export declare const RuntypeName: unique symbol; | ||
export interface Brand<B extends string, A extends Runtype> extends Runtype<Static<A> & { | ||
export interface Brand<B extends string, A extends RuntypeBase<unknown>> extends Codec<Static<A> & { | ||
[RuntypeName]: B; | ||
}> { | ||
tag: 'brand'; | ||
brand: B; | ||
entity: A; | ||
readonly tag: 'brand'; | ||
readonly brand: B; | ||
readonly entity: A; | ||
} | ||
export declare function Brand<B extends string, A extends Runtype>(brand: B, entity: A): Brand<B, A>; | ||
export declare function isBrandRuntype(runtype: RuntypeBase): runtype is Brand<string, RuntypeBase>; | ||
export declare function Brand<B extends string, A extends RuntypeBase<unknown>>(brand: B, entity: A): Brand<B, A>; |
@@ -1,18 +0,21 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
import { RuntypeBase, Static, Codec } from '../runtype'; | ||
import { Unknown } from './unknown'; | ||
export declare type ConstraintCheck<A extends Runtype> = (x: Static<A>) => boolean | string; | ||
export interface Constraint<A extends Runtype, T extends Static<A> = Static<A>, K = unknown> extends Runtype<T> { | ||
tag: 'constraint'; | ||
underlying: A; | ||
constraint(x: Static<A>): boolean | string; | ||
export declare type ConstraintCheck<A extends RuntypeBase<unknown>> = (x: Static<A>) => boolean | string; | ||
export declare function isConstraintRuntype(runtype: RuntypeBase): runtype is Constraint<RuntypeBase, unknown, unknown>; | ||
export interface Constraint<TUnderlying extends RuntypeBase<unknown>, TConstrained extends Static<TUnderlying> = Static<TUnderlying>, TArgs = unknown> extends Codec<TConstrained> { | ||
readonly tag: 'constraint'; | ||
readonly underlying: TUnderlying; | ||
constraint(x: Static<TUnderlying>): boolean | string; | ||
readonly name?: string; | ||
readonly args?: TArgs; | ||
} | ||
export declare function Constraint<TUnderlying extends RuntypeBase<unknown>, TConstrained extends Static<TUnderlying> = Static<TUnderlying>, TArgs = unknown>(underlying: TUnderlying, constraint: ConstraintCheck<TUnderlying>, options?: { | ||
name?: string; | ||
args?: K; | ||
args?: TArgs; | ||
}): Constraint<TUnderlying, TConstrained, TArgs>; | ||
export interface Guard<TConstrained, TArgs = unknown> extends Constraint<Unknown, TConstrained, TArgs> { | ||
} | ||
export declare function Constraint<A extends Runtype, T extends Static<A> = Static<A>, K = unknown>(underlying: A, constraint: ConstraintCheck<A>, options?: { | ||
name?: string; | ||
args?: K; | ||
}): Constraint<A, T, K>; | ||
export declare const Guard: <T, K = unknown>(guard: (x: unknown) => x is T, options?: { | ||
export declare const Guard: <T, K = unknown>(test: (x: unknown) => x is T, options?: { | ||
name?: string | undefined; | ||
args?: K | undefined; | ||
} | undefined) => Constraint<Unknown, T, K>; | ||
} | undefined) => Guard<T, K>; |
@@ -1,20 +0,14 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
export interface StringDictionary<V extends Runtype> extends Runtype<{ | ||
[_: string]: Static<V>; | ||
}> { | ||
tag: 'dictionary'; | ||
key: 'string'; | ||
value: V; | ||
import { String, Number, Record } from '..'; | ||
import { RuntypeBase } from '../runtype'; | ||
export interface StringDictionary<V extends RuntypeBase> extends Record<String, V> { | ||
} | ||
export interface NumberDictionary<V extends Runtype> extends Runtype<{ | ||
[_: number]: Static<V>; | ||
}> { | ||
tag: 'dictionary'; | ||
key: 'number'; | ||
value: V; | ||
export interface NumberDictionary<V extends RuntypeBase> extends Record<Number, V> { | ||
} | ||
/** | ||
* Construct a runtype for arbitrary dictionaries. | ||
* @deprecated use Record(String, value) | ||
*/ | ||
export declare function Dictionary<V extends Runtype>(value: V, key?: 'string'): StringDictionary<V>; | ||
export declare function Dictionary<V extends Runtype>(value: V, key?: 'number'): NumberDictionary<V>; | ||
export declare function Dictionary<V extends RuntypeBase>(value: V, key?: 'string'): StringDictionary<V>; | ||
/** | ||
* @deprecated use Record(Number, value) | ||
*/ | ||
export declare function Dictionary<V extends RuntypeBase>(value: V, key?: 'number'): NumberDictionary<V>; |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface Function extends Runtype<(...args: any[]) => any> { | ||
tag: 'function'; | ||
import { Codec } from '../runtype'; | ||
export interface Function extends Codec<(...args: any[]) => any> { | ||
readonly tag: 'function'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,9 +0,9 @@ | ||
import { Runtype } from '../runtype'; | ||
import { Codec } from '../runtype'; | ||
export interface Constructor<V> { | ||
new (...args: any[]): V; | ||
} | ||
export interface InstanceOf<V> extends Runtype<V> { | ||
tag: 'instanceof'; | ||
ctor: Constructor<V>; | ||
export interface InstanceOf<V = unknown> extends Codec<V> { | ||
readonly tag: 'instanceof'; | ||
readonly ctor: Constructor<V>; | ||
} | ||
export declare function InstanceOf<V>(ctor: Constructor<V>): InstanceOf<V>; |
@@ -1,54 +0,12 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
export interface Intersect1<A extends Runtype> extends Runtype<Static<A>> { | ||
tag: 'intersect'; | ||
intersectees: [A]; | ||
import { Static, RuntypeBase, Codec } from '../runtype'; | ||
export declare type StaticIntersect<TIntersectees extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TIntersectees]: TIntersectees[key] extends RuntypeBase ? (parameter: Static<TIntersectees[key]>) => any : unknown; | ||
}[number] extends (k: infer I) => void ? I : never; | ||
export interface Intersect<TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]> extends Codec<StaticIntersect<TIntersectees>> { | ||
readonly tag: 'intersect'; | ||
readonly intersectees: TIntersectees; | ||
} | ||
export interface Intersect2<A extends Runtype, B extends Runtype> extends Runtype<Static<A> & Static<B>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B]; | ||
} | ||
export interface Intersect3<A extends Runtype, B extends Runtype, C extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C]; | ||
} | ||
export interface Intersect4<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D]; | ||
} | ||
export interface Intersect5<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E]; | ||
} | ||
export interface Intersect6<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F]; | ||
} | ||
export interface Intersect7<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G]; | ||
} | ||
export interface Intersect8<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G> & Static<H>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H]; | ||
} | ||
export interface Intersect9<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G> & Static<H> & Static<I>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H, I]; | ||
} | ||
export interface Intersect10<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype, J extends Runtype> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G> & Static<H> & Static<I> & Static<J>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H, I, J]; | ||
} | ||
/** | ||
* Construct an intersection runtype from runtypes for its alternatives. | ||
*/ | ||
export declare function Intersect<A extends Runtype>(A: A): Intersect1<A>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype>(A: A, B: B): Intersect2<A, B>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype>(A: A, B: B, C: C): Intersect3<A, B, C>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype>(A: A, B: B, C: C, D: D): Intersect4<A, B, C, D>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype>(A: A, B: B, C: C, D: D, E: E): Intersect5<A, B, C, D, E>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F): Intersect6<A, B, C, D, E, F>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Intersect7<A, B, C, D, E, F, G>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Intersect8<A, B, C, D, E, F, G, H>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Intersect9<A, B, C, D, E, F, G, H, I>; | ||
export declare function Intersect<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype, J extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J): Intersect10<A, B, C, D, E, F, G, H, I, J>; | ||
export declare function Intersect<TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]>(...intersectees: TIntersectees): Intersect<TIntersectees>; |
@@ -1,5 +0,11 @@ | ||
import { Runtype } from '../runtype'; | ||
import { RuntypeBase, Codec, Static } from '../runtype'; | ||
export interface Lazy<TUnderlying extends RuntypeBase<unknown>> extends Codec<Static<TUnderlying>> { | ||
readonly tag: 'lazy'; | ||
readonly underlying: () => TUnderlying; | ||
} | ||
export declare function lazyValue<T>(fn: () => T): () => T; | ||
export declare function isLazyRuntype(runtype: RuntypeBase): runtype is Lazy<RuntypeBase>; | ||
/** | ||
* Construct a possibly-recursive Runtype. | ||
*/ | ||
export declare function Lazy<A extends Runtype>(delayed: () => A): A; | ||
export declare function Lazy<TUnderlying extends RuntypeBase<unknown>>(delayed: () => TUnderlying): Lazy<TUnderlying>; |
@@ -1,14 +0,15 @@ | ||
import { Runtype } from '../runtype'; | ||
import { RuntypeBase, Codec } from '../runtype'; | ||
/** | ||
* The super type of all literal types. | ||
*/ | ||
export declare type LiteralBase = undefined | null | boolean | number | string; | ||
export interface Literal<A extends LiteralBase> extends Runtype<A> { | ||
tag: 'literal'; | ||
value: A; | ||
export declare type LiteralValue = undefined | null | boolean | number | string; | ||
export interface Literal<TLiteralValue extends LiteralValue = LiteralValue> extends Codec<TLiteralValue> { | ||
readonly tag: 'literal'; | ||
readonly value: TLiteralValue; | ||
} | ||
export declare function isLiteralRuntype(runtype: RuntypeBase): runtype is Literal; | ||
/** | ||
* Construct a runtype for a type literal. | ||
*/ | ||
export declare function Literal<A extends LiteralBase>(valueBase: A): Literal<A>; | ||
export declare function Literal<A extends LiteralValue>(valueBase: A): Literal<A>; | ||
/** | ||
@@ -15,0 +16,0 @@ * An alias for Literal(undefined). |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface Never extends Runtype<never> { | ||
tag: 'never'; | ||
import { Codec } from '../runtype'; | ||
export interface Never extends Codec<never> { | ||
readonly tag: 'never'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface Number extends Runtype<number> { | ||
tag: 'number'; | ||
import { Codec } from '../runtype'; | ||
export interface Number extends Codec<number> { | ||
readonly tag: 'number'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface String extends Runtype<string> { | ||
tag: 'string'; | ||
import { Codec } from '../runtype'; | ||
export interface String extends Codec<string> { | ||
readonly tag: 'string'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
interface Sym extends Runtype<symbol> { | ||
tag: 'symbol'; | ||
import { Codec } from '../runtype'; | ||
interface Sym extends Codec<symbol> { | ||
readonly tag: 'symbol'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -1,59 +0,13 @@ | ||
import { Runtype, Static } from '../runtype'; | ||
export interface Tuple0 extends Runtype { | ||
tag: 'tuple'; | ||
components: []; | ||
import { RuntypeBase, Codec } from '../runtype'; | ||
export declare type StaticTuple<TElements extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TElements]: TElements[key] extends RuntypeBase<infer E> ? E : unknown; | ||
}; | ||
export interface Tuple<TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[]> extends Codec<StaticTuple<TElements>> { | ||
readonly tag: 'tuple'; | ||
readonly components: TElements; | ||
} | ||
export interface Tuple1<A extends Runtype> extends Runtype<[Static<A>]> { | ||
tag: 'tuple'; | ||
components: [A]; | ||
} | ||
export interface Tuple2<A extends Runtype, B extends Runtype> extends Runtype<[Static<A>, Static<B>]> { | ||
tag: 'tuple'; | ||
components: [A, B]; | ||
} | ||
export interface Tuple3<A extends Runtype, B extends Runtype, C extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C]; | ||
} | ||
export interface Tuple4<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D]; | ||
} | ||
export interface Tuple5<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E]; | ||
} | ||
export interface Tuple6<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F]; | ||
} | ||
export interface Tuple7<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G]; | ||
} | ||
export interface Tuple8<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>, Static<H>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H]; | ||
} | ||
export interface Tuple9<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>, Static<H>, Static<I>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H, I]; | ||
} | ||
export interface Tuple10<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype, J extends Runtype> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>, Static<H>, Static<I>, Static<J>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H, I, J]; | ||
} | ||
export declare function isTupleRuntype(runtype: RuntypeBase): runtype is Tuple<readonly RuntypeBase[]>; | ||
/** | ||
* Construct a tuple runtype from runtypes for each of its elements. | ||
*/ | ||
export declare function Tuple(): Tuple0; | ||
export declare function Tuple<A extends Runtype>(A: A): Tuple1<A>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype>(A: A, B: B): Tuple2<A, B>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype>(A: A, B: B, C: C): Tuple3<A, B, C>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype>(A: A, B: B, C: C, D: D): Tuple4<A, B, C, D>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype>(A: A, B: B, C: C, D: D, E: E): Tuple5<A, B, C, D, E>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F): Tuple6<A, B, C, D, E, F>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Tuple7<A, B, C, D, E, F, G>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Tuple8<A, B, C, D, E, F, G, H>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Tuple9<A, B, C, D, E, F, G, H, I>; | ||
export declare function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype, E extends Runtype, F extends Runtype, G extends Runtype, H extends Runtype, I extends Runtype, J extends Runtype>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J): Tuple10<A, B, C, D, E, F, G, H, I, J>; | ||
export declare function Tuple<T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly []>(...components: T): Tuple<T>; |
@@ -1,205 +0,22 @@ | ||
import { Runtype as Rt, Static } from '../runtype'; | ||
export interface Union1<A extends Rt> extends Rt<Static<A>> { | ||
tag: 'union'; | ||
alternatives: [A]; | ||
match: Match1<A>; | ||
import { Codec, Static, RuntypeBase } from '../runtype'; | ||
export declare type StaticUnion<TAlternatives extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TAlternatives]: TAlternatives[key] extends RuntypeBase<unknown> ? Static<TAlternatives[key]> : unknown; | ||
}[number]; | ||
export interface Union<TAlternatives extends readonly RuntypeBase<unknown>[]> extends Codec<StaticUnion<TAlternatives>> { | ||
readonly tag: 'union'; | ||
readonly alternatives: TAlternatives; | ||
match: Match<TAlternatives>; | ||
} | ||
export interface Union2<A extends Rt, B extends Rt> extends Rt<Static<A> | Static<B>> { | ||
tag: 'union'; | ||
alternatives: [A, B]; | ||
match: Match2<A, B>; | ||
} | ||
export interface Union3<A extends Rt, B extends Rt, C extends Rt> extends Rt<Static<A> | Static<B> | Static<C>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C]; | ||
match: Match3<A, B, C>; | ||
} | ||
export interface Union4<A extends Rt, B extends Rt, C extends Rt, D extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D]; | ||
match: Match4<A, B, C, D>; | ||
} | ||
export interface Union5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E]; | ||
match: Match5<A, B, C, D, E>; | ||
} | ||
export interface Union6<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F]; | ||
match: Match6<A, B, C, D, E, F>; | ||
} | ||
export interface Union7<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G]; | ||
match: Match7<A, B, C, D, E, F, G>; | ||
} | ||
export interface Union8<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H]; | ||
match: Match8<A, B, C, D, E, F, G, H>; | ||
} | ||
export interface Union9<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I]; | ||
match: Match9<A, B, C, D, E, F, G, H, I>; | ||
} | ||
export interface Union10<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J]; | ||
match: Match10<A, B, C, D, E, F, G, H, I, J>; | ||
} | ||
export interface Union11<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K]; | ||
match: Match11<A, B, C, D, E, F, G, H, I, J, K>; | ||
} | ||
export interface Union12<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L]; | ||
match: Match12<A, B, C, D, E, F, G, H, I, J, K, L>; | ||
} | ||
export interface Union13<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M]; | ||
match: Match13<A, B, C, D, E, F, G, H, I, J, K, L, M>; | ||
} | ||
export interface Union14<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N]; | ||
match: Match14<A, B, C, D, E, F, G, H, I, J, K, L, M, N>; | ||
} | ||
export interface Union15<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]; | ||
match: Match15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>; | ||
} | ||
export interface Union16<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]; | ||
match: Match16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>; | ||
} | ||
export interface Union17<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]; | ||
match: Match17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>; | ||
} | ||
export interface Union18<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]; | ||
match: Match18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R>; | ||
} | ||
export interface Union19<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R> | Static<S>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]; | ||
match: Match19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S>; | ||
} | ||
export interface Union20<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt, T extends Rt> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R> | Static<S> | Static<T>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]; | ||
match: Match20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T>; | ||
} | ||
/** | ||
* Construct a union runtype from runtypes for its alternatives. | ||
*/ | ||
export declare function Union<A extends Rt>(A: A): Union1<A>; | ||
export declare function Union<A extends Rt, B extends Rt>(A: A, B: B): Union2<A, B>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt>(A: A, B: B, C: C): Union3<A, B, C>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt>(A: A, B: B, C: C, D: D): Union4<A, B, C, D>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt>(A: A, B: B, C: C, D: D, E: E): Union5<A, B, C, D, E>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F): Union6<A, B, C, D, E, F>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Union7<A, B, C, D, E, F, G>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Union8<A, B, C, D, E, F, G, H>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Union9<A, B, C, D, E, F, G, H, I>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J): Union10<A, B, C, D, E, F, G, H, I, J>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K): Union11<A, B, C, D, E, F, G, H, I, J, K>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L): Union12<A, B, C, D, E, F, G, H, I, J, K, L>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M): Union13<A, B, C, D, E, F, G, H, I, J, K, L, M>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N): Union14<A, B, C, D, E, F, G, H, I, J, K, L, M, N>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O): Union15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O, P: P): Union16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O, P: P, Q: Q): Union17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O, P: P, Q: Q, R: R): Union18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O, P: P, Q: Q, R: R, S: S): Union19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S>; | ||
export declare function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt, T extends Rt>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L, M: M, N: N, O: O, P: P, Q: Q, R: R, S: S, T: T): Union20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T>; | ||
export interface Match1<A extends Rt> { | ||
<Z>(a: Case<A, Z>): Matcher1<A, Z>; | ||
export declare function Union<TAlternatives extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]]>(...alternatives: TAlternatives): Union<TAlternatives>; | ||
export interface Match<A extends readonly RuntypeBase<unknown>[]> { | ||
<Z>(...a: { | ||
[key in keyof A]: A[key] extends RuntypeBase<unknown> ? Case<A[key], Z> : never; | ||
}): Matcher<A, Z>; | ||
} | ||
export interface Match2<A extends Rt, B extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>): Matcher2<A, B, Z>; | ||
} | ||
export interface Match3<A extends Rt, B extends Rt, C extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>): Matcher3<A, B, C, Z>; | ||
} | ||
export interface Match4<A extends Rt, B extends Rt, C extends Rt, D extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>): Matcher4<A, B, C, D, Z>; | ||
} | ||
export interface Match5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>): Matcher5<A, B, C, D, E, Z>; | ||
} | ||
export interface Match6<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>): Matcher6<A, B, C, D, E, F, Z>; | ||
} | ||
export interface Match7<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>, g: Case<G, Z>): Matcher7<A, B, C, D, E, F, G, Z>; | ||
} | ||
export interface Match8<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>, g: Case<G, Z>, h: Case<H, Z>): Matcher8<A, B, C, D, E, F, G, H, Z>; | ||
} | ||
export interface Match9<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>, g: Case<G, Z>, h: Case<H, Z>, i: Case<I, Z>): Matcher9<A, B, C, D, E, F, G, H, I, Z>; | ||
} | ||
export interface Match10<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>, g: Case<G, Z>, h: Case<H, Z>, i: Case<I, Z>, j: Case<J, Z>): Matcher10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
} | ||
export interface Match11<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>, f: Case<F, Z>, g: Case<G, Z>, h: Case<H, Z>, i: Case<I, Z>, j: Case<J, Z>, k: Case<K, Z>): Matcher11<A, B, C, D, E, F, G, H, I, J, K, Z>; | ||
} | ||
export interface Match12<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>): Matcher12<A, B, C, D, E, F, G, H, I, J, K, L, Z>; | ||
} | ||
export interface Match13<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>): Matcher13<A, B, C, D, E, F, G, H, I, J, K, L, M, Z>; | ||
} | ||
export interface Match14<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>): Matcher14<A, B, C, D, E, F, G, H, I, J, K, L, M, N, Z>; | ||
} | ||
export interface Match15<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>): Matcher15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, Z>; | ||
} | ||
export interface Match16<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>, P: Case<P, Z>): Matcher16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Z>; | ||
} | ||
export interface Match17<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>, P: Case<P, Z>, Q: Case<Q, Z>): Matcher17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, Z>; | ||
} | ||
export interface Match18<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>, P: Case<P, Z>, Q: Case<Q, Z>, R: Case<R, Z>): Matcher18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, Z>; | ||
} | ||
export interface Match19<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>, P: Case<P, Z>, Q: Case<Q, Z>, R: Case<R, Z>, S: Case<S, Z>): Matcher19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, Z>; | ||
} | ||
export interface Match20<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt, T extends Rt> { | ||
<Z>(A: Case<A, Z>, B: Case<B, Z>, C: Case<C, Z>, D: Case<D, Z>, E: Case<E, Z>, F: Case<F, Z>, G: Case<G, Z>, H: Case<H, Z>, I: Case<I, Z>, J: Case<J, Z>, K: Case<K, Z>, L: Case<L, Z>, M: Case<M, Z>, N: Case<N, Z>, O: Case<O, Z>, P: Case<P, Z>, Q: Case<Q, Z>, R: Case<R, Z>, S: Case<S, Z>, T: Case<T, Z>): Matcher20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, Z>; | ||
} | ||
export declare type Case<T extends Rt, Result> = (v: Static<T>) => Result; | ||
export declare type Matcher1<A extends Rt, Z> = (x: Static<A>) => Z; | ||
export declare type Matcher2<A extends Rt, B extends Rt, Z> = (x: Static<A> | Static<B>) => Z; | ||
export declare type Matcher3<A extends Rt, B extends Rt, C extends Rt, Z> = (x: Static<A> | Static<B> | Static<C>) => Z; | ||
export declare type Matcher4<A extends Rt, B extends Rt, C extends Rt, D extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D>) => Z; | ||
export declare type Matcher5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E>) => Z; | ||
export declare type Matcher6<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F>) => Z; | ||
export declare type Matcher7<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G>) => Z; | ||
export declare type Matcher8<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H>) => Z; | ||
export declare type Matcher9<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I>) => Z; | ||
export declare type Matcher10<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J>) => Z; | ||
export declare type Matcher11<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K>) => Z; | ||
export declare type Matcher12<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L>) => Z; | ||
export declare type Matcher13<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M>) => Z; | ||
export declare type Matcher14<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N>) => Z; | ||
export declare type Matcher15<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O>) => Z; | ||
export declare type Matcher16<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P>) => Z; | ||
export declare type Matcher17<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q>) => Z; | ||
export declare type Matcher18<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R>) => Z; | ||
export declare type Matcher19<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R> | Static<S>) => Z; | ||
export declare type Matcher20<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, F extends Rt, G extends Rt, H extends Rt, I extends Rt, J extends Rt, K extends Rt, L extends Rt, M extends Rt, N extends Rt, O extends Rt, P extends Rt, Q extends Rt, R extends Rt, S extends Rt, T extends Rt, Z> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | Static<I> | Static<J> | Static<K> | Static<L> | Static<M> | Static<N> | Static<O> | Static<P> | Static<Q> | Static<R> | Static<S> | Static<T>) => Z; | ||
export declare type Case<T extends RuntypeBase<unknown>, Result> = (v: Static<T>) => Result; | ||
export declare type Matcher<A extends readonly RuntypeBase<unknown>[], Z> = (x: { | ||
[key in keyof A]: A[key] extends RuntypeBase<infer Type> ? Type : unknown; | ||
}[number]) => Z; |
@@ -1,4 +0,4 @@ | ||
import { Runtype } from '../runtype'; | ||
export interface Unknown extends Runtype { | ||
tag: 'unknown'; | ||
import { Codec } from '../runtype'; | ||
export interface Unknown extends Codec<unknown> { | ||
readonly tag: 'unknown'; | ||
} | ||
@@ -5,0 +5,0 @@ /** |
@@ -0,0 +0,0 @@ import { Unknown } from './unknown'; |
export declare function hasKey<K extends string>(k: K, o: {}): o is { | ||
[_ in K]: {}; | ||
}; |
{ | ||
"name": "funtypes", | ||
"version": "1.0.0", | ||
"version": "2.0.0", | ||
"description": "Runtime validation for static types", | ||
"main": "./lib/index.js", | ||
"module": "./lib/index.mjs", | ||
"types": "./lib/index.d.ts", | ||
"scripts": { | ||
"build": "tsc --pretty", | ||
"postbuild": "tsc --noEmit && rimraf lib/**/*.spec.*", | ||
"build": "rollup -c", | ||
"format": "node scripts/format.js", | ||
@@ -20,5 +22,9 @@ "test": "jest $([ \"$CI\" = true ] && echo --coverage || echo --watch)", | ||
"jest": "24.9.0", | ||
"prettier": "^1.19.1", | ||
"prettier": "^2.1.1", | ||
"rollup": "^2.26.11", | ||
"rollup-plugin-size-snapshot": "^0.12.0", | ||
"rollup-plugin-typescript2": "^0.27.2", | ||
"ts-jest": "^24.1.0", | ||
"typescript": "3.7.5" | ||
"type-assertions": "^1.1.0", | ||
"typescript": "4.0.2" | ||
}, | ||
@@ -46,4 +52,3 @@ "keywords:": [ | ||
"testEnvironment": "node" | ||
}, | ||
"dependencies": {} | ||
} | ||
} |
@@ -10,2 +10,3 @@ # Funtypes | ||
[![Build Status](https://img.shields.io/github/workflow/status/ForbesLindesay/funtypes/Test/master?style=for-the-badge)](https://github.com/ForbesLindesay/funtypes/actions?query=workflow%3ATest+branch%3Amaster) | ||
[![Coveralls github branch](https://img.shields.io/coveralls/github/ForbesLindesay/funtypes/master?color=brightgreen&style=for-the-badge)](https://coveralls.io/github/ForbesLindesay/funtypes) | ||
[![Rolling Versions](https://img.shields.io/badge/Rolling%20Versions-Enabled-brightgreen?style=for-the-badge)](https://rollingversions.com/ForbesLindesay/funtypes) | ||
@@ -68,7 +69,7 @@ [![NPM version](https://img.shields.io/npm/v/funtypes?style=for-the-badge)](https://www.npmjs.com/package/funtypes) | ||
```ts | ||
import { Boolean, Number, String, Literal, Array, Tuple, Record, Union } from 'funtypes'; | ||
import { Boolean, Number, String, Literal, Array, Tuple, Object, Union } from 'funtypes'; | ||
const Vector = Tuple(Number, Number, Number); | ||
const Asteroid = Record({ | ||
const Asteroid = Object({ | ||
type: Literal('asteroid'), | ||
@@ -79,3 +80,3 @@ location: Vector, | ||
const Planet = Record({ | ||
const Planet = Object({ | ||
type: Literal('planet'), | ||
@@ -95,3 +96,3 @@ location: Vector, | ||
const CrewMember = Record({ | ||
const CrewMember = Object({ | ||
name: String, | ||
@@ -103,3 +104,3 @@ age: Number, | ||
const Ship = Record({ | ||
const Ship = Object({ | ||
type: Literal('ship'), | ||
@@ -165,3 +166,3 @@ location: Vector, | ||
function disembark(obj: {}) { | ||
if (SpaceObject.guard(obj)) { | ||
if (SpaceObject.test(obj)) { | ||
// obj: SpaceObject | ||
@@ -273,3 +274,3 @@ if (obj.type === 'ship') { | ||
use a lowest-common-denominator type that will pass validation for all expected | ||
inputs of your constraint function or type guard. If there's no obvious | ||
inputs of your constraint function or type test. If there's no obvious | ||
lowest-common-denominator type, you can always use `Unknown` as the underlying | ||
@@ -321,3 +322,3 @@ type, as shown in the `Buffer` examples above. | ||
If a `Record` may or may not have some keys, we can declare the optional | ||
If a `Object` may or may not have some keys, we can declare the optional | ||
keys using `myRecord.And(Partial({ ... }))`. Partial keys validate successfully if | ||
@@ -329,3 +330,3 @@ they are absent or undefined (but not null) or the type specified | ||
// Using `Ship` from above | ||
const RegisteredShip = Ship.And(Record({ | ||
const RegisteredShip = Ship.And(Object({ | ||
// All registered ships must have this flag | ||
@@ -344,6 +345,6 @@ isRegistered: Literal(true), | ||
If a record has keys which _must be present_ but can be null, then use | ||
the `Record` runtype normally instead. | ||
the `Object` runtype normally instead. | ||
```ts | ||
const MilitaryShip = Ship.And(Record({ | ||
const MilitaryShip = Ship.And(Object({ | ||
shipClass: Literal('military'), | ||
@@ -358,3 +359,3 @@ | ||
Array and Record funtypes have a special function `.asReadonly()`, that creates a new runtype where the values are readonly. | ||
Array and Object funtypes have a special function `.asReadonly()`, that creates a new runtype where the values are readonly. | ||
@@ -364,3 +365,3 @@ For example: | ||
```typescript | ||
const Asteroid = Record({ | ||
const Asteroid = Object({ | ||
type: Literal('asteroid'), | ||
@@ -367,0 +368,0 @@ location: Vector, |
@@ -13,5 +13,3 @@ 'use strict'; | ||
const npmBinPath = execSync('npm bin') | ||
.toString() | ||
.trim(); | ||
const npmBinPath = execSync('npm bin').toString().trim(); | ||
@@ -18,0 +16,0 @@ const command = [ |
import { AsyncContract, Number } from '.'; | ||
import { ValidationError } from './errors'; | ||
describe('AsyncContract', () => { | ||
describe('when function does not return a promise', () => { | ||
it('throws a validation error', () => { | ||
const contractedFunction = AsyncContract(Number).enforce(() => 7 as any); | ||
expect(contractedFunction).toThrow(ValidationError); | ||
it('throws a validation error', async () => { | ||
const contractedFunction = AsyncContract([], Number).enforce(() => 7 as any); | ||
await expect(contractedFunction()).rejects.toMatchInlineSnapshot( | ||
`[ValidationError: Expected function to return a promise, but instead got 7]`, | ||
); | ||
}); | ||
@@ -13,14 +14,13 @@ }); | ||
it('throws a validation error asynchronously', async () => { | ||
const contractedFunction = AsyncContract(Number).enforce(() => Promise.resolve('hi' as any)); | ||
try { | ||
await contractedFunction(); | ||
fail(); | ||
} catch (e) { | ||
expect(e).toBeInstanceOf(ValidationError); | ||
} | ||
const contractedFunction = AsyncContract([], Number).enforce(() => | ||
Promise.resolve('hi' as any), | ||
); | ||
await expect(contractedFunction()).rejects.toMatchInlineSnapshot( | ||
`[ValidationError: Expected number, but was string]`, | ||
); | ||
}); | ||
}); | ||
describe('when a function does return a promise', () => { | ||
describe('when a function does return a promise, for the correct type', () => { | ||
it('should validate successfully', async () => { | ||
const contractedFunction = AsyncContract(Number).enforce(() => Promise.resolve(7)); | ||
const contractedFunction = AsyncContract([], Number).enforce(() => Promise.resolve(7)); | ||
await expect(contractedFunction()).resolves.toBe(7); | ||
@@ -30,7 +30,29 @@ }); | ||
describe('when not enough arguments are provided', () => { | ||
it('throws a validation error', () => { | ||
const contractedFunction = AsyncContract(Number, Number).enforce(n => Promise.resolve(n + 1)); | ||
expect(contractedFunction).toThrow(ValidationError); | ||
it('throws a validation error', async () => { | ||
const contractedFunction = AsyncContract([Number], Number).enforce(n => | ||
Promise.resolve(n + 1), | ||
); | ||
await expect((contractedFunction as any)()).rejects.toMatchInlineSnapshot( | ||
`[ValidationError: Expected 1 arguments but only received 0]`, | ||
); | ||
}); | ||
}); | ||
describe('when arguments are of the wrong type', () => { | ||
it('throws a validation error', async () => { | ||
const contractedFunction = AsyncContract([Number], Number).enforce(n => | ||
Promise.resolve(n + 1), | ||
); | ||
await expect(contractedFunction('whatever' as any)).rejects.toMatchInlineSnapshot( | ||
`[ValidationError: Expected number, but was string]`, | ||
); | ||
}); | ||
}); | ||
describe('when arguments are valid', () => { | ||
it('throws a validation error', async () => { | ||
const contractedFunction = AsyncContract([Number], Number).enforce(n => | ||
Promise.resolve(n + 1), | ||
); | ||
await expect(contractedFunction(41)).resolves.toEqual(42); | ||
}); | ||
}); | ||
}); |
@@ -1,165 +0,57 @@ | ||
import { Runtype } from './index'; | ||
import { ValidationError } from './errors'; | ||
import { | ||
createGuardVisitedState, | ||
createVisitedState, | ||
innerGuard, | ||
innerValidate, | ||
OpaqueVisitedState, | ||
RuntypeBase, | ||
} from './runtype'; | ||
export interface AsyncContract0<Z> { | ||
enforce(f: () => Promise<Z>): () => Promise<Z>; | ||
export interface AsyncContract<A extends any[], Z> { | ||
enforce(f: (...a: A) => Promise<Z>): (...a: A) => Promise<Z>; | ||
} | ||
export interface AsyncContract1<A, Z> { | ||
enforce(f: (a: A) => Promise<Z>): (a: A) => Promise<Z>; | ||
} | ||
export interface AsyncContract2<A, B, Z> { | ||
enforce(f: (a: A, b: B) => Promise<Z>): (a: A, b: B) => Promise<Z>; | ||
} | ||
export interface AsyncContract3<A, B, C, Z> { | ||
enforce(f: (a: A, b: B, c: C) => Promise<Z>): (a: A, b: B, c: C) => Promise<Z>; | ||
} | ||
export interface AsyncContract4<A, B, C, D, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D) => Promise<Z>): (a: A, b: B, c: C, d: D) => Promise<Z>; | ||
} | ||
export interface AsyncContract5<A, B, C, D, E, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E) => Promise<Z>; | ||
} | ||
export interface AsyncContract6<A, B, C, D, E, F, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F) => Promise<Z>; | ||
} | ||
export interface AsyncContract7<A, B, C, D, E, F, G, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Promise<Z>; | ||
} | ||
export interface AsyncContract8<A, B, C, D, E, F, G, H, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Promise<Z>; | ||
} | ||
export interface AsyncContract9<A, B, C, D, E, F, G, H, I, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Promise<Z>; | ||
} | ||
export interface AsyncContract10<A, B, C, D, E, F, G, H, I, J, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<Z>, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Promise<Z>; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
export function AsyncContract<Z>(Z: Runtype<Z>): AsyncContract0<Z>; | ||
export function AsyncContract<A, Z>(A: Runtype<A>, Z: Runtype<Z>): AsyncContract1<A, Z>; | ||
export function AsyncContract<A, B, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
Z: Runtype<Z>, | ||
): AsyncContract2<A, B, Z>; | ||
export function AsyncContract<A, B, C, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
Z: Runtype<Z>, | ||
): AsyncContract3<A, B, C, Z>; | ||
export function AsyncContract<A, B, C, D, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
Z: Runtype<Z>, | ||
): AsyncContract4<A, B, C, D, Z>; | ||
export function AsyncContract<A, B, C, D, E, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
Z: Runtype<Z>, | ||
): AsyncContract5<A, B, C, D, E, Z>; | ||
export function AsyncContract<A, B, C, D, E, F, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
Z: Runtype<Z>, | ||
): AsyncContract6<A, B, C, D, E, F, Z>; | ||
export function AsyncContract<A, B, C, D, E, F, G, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
Z: Runtype<Z>, | ||
): AsyncContract7<A, B, C, D, E, F, G, Z>; | ||
export function AsyncContract<A, B, C, D, E, F, G, H, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
Z: Runtype<Z>, | ||
): AsyncContract8<A, B, C, D, E, F, G, H, Z>; | ||
export function AsyncContract<A, B, C, D, E, F, G, H, I, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
I: Runtype<I>, | ||
Z: Runtype<Z>, | ||
): AsyncContract9<A, B, C, D, E, F, G, H, I, Z>; | ||
export function AsyncContract<A, B, C, D, E, F, G, H, I, J, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
I: Runtype<I>, | ||
J: Runtype<J>, | ||
Z: Runtype<Z>, | ||
): AsyncContract10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
export function AsyncContract(...runtypes: Runtype[]) { | ||
const lastIndex = runtypes.length - 1; | ||
const argTypes = runtypes.slice(0, lastIndex); | ||
const returnType = runtypes[lastIndex]; | ||
export function AsyncContract<A extends [any, ...any[]] | [], Z>( | ||
argTypes: { [key in keyof A]: key extends 'length' ? A['length'] : RuntypeBase<A[key]> }, | ||
returnType: RuntypeBase<Z>, | ||
): AsyncContract<A, Z> { | ||
return { | ||
enforce: (f: (...args: any[]) => any) => (...args: any[]) => { | ||
if (args.length < argTypes.length) | ||
throw new ValidationError( | ||
`Expected ${argTypes.length} arguments but only received ${args.length}`, | ||
if (args.length < argTypes.length) { | ||
return Promise.reject( | ||
new ValidationError( | ||
`Expected ${argTypes.length} arguments but only received ${args.length}`, | ||
), | ||
); | ||
for (let i = 0; i < argTypes.length; i++) argTypes[i].check(args[i]); | ||
} | ||
const visited: OpaqueVisitedState = createVisitedState(); | ||
for (let i = 0; i < argTypes.length; i++) { | ||
const result = innerValidate(argTypes[i], args[i], visited); | ||
if (result.success) { | ||
args[i] = result.value; | ||
} else { | ||
return Promise.reject(new ValidationError(result.message, result.key)); | ||
} | ||
} | ||
const returnedPromise = f(...args); | ||
if (!(returnedPromise instanceof Promise)) | ||
throw new ValidationError( | ||
`Expected function to return a promise, but instead got ${returnedPromise}`, | ||
if (!(returnedPromise instanceof Promise)) { | ||
return Promise.reject( | ||
new ValidationError( | ||
`Expected function to return a promise, but instead got ${returnedPromise}`, | ||
), | ||
); | ||
return returnedPromise.then(returnType.check); | ||
} | ||
return returnedPromise.then(value => { | ||
const result = innerGuard(returnType, value, createGuardVisitedState()); | ||
if (result) { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
return value; | ||
}); | ||
}, | ||
}; | ||
} |
@@ -1,144 +0,24 @@ | ||
import { Runtype } from './index'; | ||
import { | ||
createGuardVisitedState, | ||
createVisitedState, | ||
innerGuard, | ||
innerValidate, | ||
OpaqueVisitedState, | ||
RuntypeBase, | ||
} from './runtype'; | ||
import { ValidationError } from './errors'; | ||
export interface Contract0<Z> { | ||
enforce(f: () => Z): () => Z; | ||
export interface Contract<A extends any[], Z> { | ||
enforce(f: (...a: A) => Z): (...a: A) => Z; | ||
} | ||
export interface Contract1<A, Z> { | ||
enforce(f: (a: A) => Z): (a: A) => Z; | ||
} | ||
export interface Contract2<A, B, Z> { | ||
enforce(f: (a: A, b: B) => Z): (a: A, b: B) => Z; | ||
} | ||
export interface Contract3<A, B, C, Z> { | ||
enforce(f: (a: A, b: B, c: C) => Z): (a: A, b: B, c: C) => Z; | ||
} | ||
export interface Contract4<A, B, C, D, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D) => Z): (a: A, b: B, c: C, d: D) => Z; | ||
} | ||
export interface Contract5<A, B, C, D, E, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E) => Z): (a: A, b: B, c: C, d: D, e: E) => Z; | ||
} | ||
export interface Contract6<A, B, C, D, E, F, Z> { | ||
enforce(f: (a: A, b: B, c: C, d: D, e: E, f: F) => Z): (a: A, b: B, c: C, d: D, e: E, f: F) => Z; | ||
} | ||
export interface Contract7<A, B, C, D, E, F, G, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Z, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G) => Z; | ||
} | ||
export interface Contract8<A, B, C, D, E, F, G, H, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Z, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H) => Z; | ||
} | ||
export interface Contract9<A, B, C, D, E, F, G, H, I, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Z, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I) => Z; | ||
} | ||
export interface Contract10<A, B, C, D, E, F, G, H, I, J, Z> { | ||
enforce( | ||
f: (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Z, | ||
): (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J) => Z; | ||
} | ||
/** | ||
* Create a function contract. | ||
*/ | ||
export function Contract<Z>(Z: Runtype<Z>): Contract0<Z>; | ||
export function Contract<A, Z>(A: Runtype<A>, Z: Runtype<Z>): Contract1<A, Z>; | ||
export function Contract<A, B, Z>(A: Runtype<A>, B: Runtype<B>, Z: Runtype<Z>): Contract2<A, B, Z>; | ||
export function Contract<A, B, C, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
Z: Runtype<Z>, | ||
): Contract3<A, B, C, Z>; | ||
export function Contract<A, B, C, D, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
Z: Runtype<Z>, | ||
): Contract4<A, B, C, D, Z>; | ||
export function Contract<A, B, C, D, E, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
Z: Runtype<Z>, | ||
): Contract5<A, B, C, D, E, Z>; | ||
export function Contract<A, B, C, D, E, F, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
Z: Runtype<Z>, | ||
): Contract6<A, B, C, D, E, F, Z>; | ||
export function Contract<A, B, C, D, E, F, G, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
Z: Runtype<Z>, | ||
): Contract7<A, B, C, D, E, F, G, Z>; | ||
export function Contract<A, B, C, D, E, F, G, H, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
Z: Runtype<Z>, | ||
): Contract8<A, B, C, D, E, F, G, H, Z>; | ||
export function Contract<A, B, C, D, E, F, G, H, I, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
I: Runtype<I>, | ||
Z: Runtype<Z>, | ||
): Contract9<A, B, C, D, E, F, G, H, I, Z>; | ||
export function Contract<A, B, C, D, E, F, G, H, I, J, Z>( | ||
A: Runtype<A>, | ||
B: Runtype<B>, | ||
C: Runtype<C>, | ||
D: Runtype<D>, | ||
E: Runtype<E>, | ||
F: Runtype<F>, | ||
G: Runtype<G>, | ||
H: Runtype<H>, | ||
I: Runtype<I>, | ||
J: Runtype<J>, | ||
Z: Runtype<Z>, | ||
): Contract10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
export function Contract(...runtypes: Runtype[]) { | ||
const lastIndex = runtypes.length - 1; | ||
const argTypes = runtypes.slice(0, lastIndex); | ||
const returnType = runtypes[lastIndex]; | ||
export function Contract<A extends [any, ...any[]] | [], Z>( | ||
argTypes: { [key in keyof A]: key extends 'length' ? A['length'] : RuntypeBase<A[key]> }, | ||
returnType: RuntypeBase<Z>, | ||
): Contract<A, Z> { | ||
return { | ||
enforce: (f: (...args: any[]) => any) => (...args: any[]) => { | ||
enforce: (f: (...args: A) => Z) => (...args: A): Z => { | ||
if (args.length < argTypes.length) | ||
@@ -148,6 +28,19 @@ throw new ValidationError( | ||
); | ||
for (let i = 0; i < argTypes.length; i++) argTypes[i].check(args[i]); | ||
return returnType.check(f(...args)); | ||
const visited: OpaqueVisitedState = createVisitedState(); | ||
for (let i = 0; i < argTypes.length; i++) { | ||
const result = innerValidate(argTypes[i], args[i], visited); | ||
if (result.success) { | ||
args[i] = result.value; | ||
} else { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
} | ||
const rawResult = f(...args); | ||
const result = innerGuard(returnType, rawResult, createGuardVisitedState()); | ||
if (result) { | ||
throw new ValidationError(result.message, result.key); | ||
} | ||
return rawResult; | ||
}, | ||
}; | ||
} |
import { | ||
Runtype, | ||
Static, | ||
Unknown, | ||
Array, | ||
Boolean, | ||
Brand, | ||
Constraint, | ||
Contract, | ||
Record, | ||
Function, | ||
Guard, | ||
InstanceOf, | ||
Intersect, | ||
Lazy, | ||
Literal, | ||
Never, | ||
Undefined, | ||
Null, | ||
Void, | ||
Boolean, | ||
Number, | ||
Partial as RTPartial, | ||
ReadonlyArray, | ||
Object as ObjectType, | ||
Runtype, | ||
Static, | ||
String, | ||
Symbol as Sym, | ||
Literal, | ||
Array, | ||
Dictionary, | ||
Record, | ||
Partial as RTPartial, | ||
Tuple, | ||
Tuple2, | ||
Undefined, | ||
Union, | ||
Union2, | ||
Intersect, | ||
Intersect2, | ||
Function, | ||
Lazy, | ||
Constraint, | ||
Contract, | ||
Reflect, | ||
InstanceOf, | ||
Brand, | ||
Guard, | ||
Unknown, | ||
Void, | ||
} from './index'; | ||
@@ -38,7 +35,7 @@ | ||
const boolTuple = Tuple(Boolean, Boolean, Boolean); | ||
const record1 = Record({ Boolean, Number }); | ||
const union1 = Union(Literal(3), String, boolTuple, record1); | ||
const object1 = ObjectType({ Boolean, Number }); | ||
const union1 = Union(Literal(3), String, boolTuple, object1); | ||
type Person = { name: string; likes: Person[] }; | ||
const Person: Runtype<Person> = Lazy(() => Record({ name: String, likes: Array(Person) })); | ||
const Person: Runtype<Person> = Lazy(() => ObjectType({ name: String, likes: Array(Person) })); | ||
const narcissist: Person = { name: 'Narcissus', likes: [] }; | ||
@@ -59,4 +56,4 @@ narcissist.likes = [narcissist]; | ||
type SRDict = { [_: string]: SRDict }; | ||
const SRDict: Runtype<SRDict> = Lazy(() => Dictionary(SRDict)); | ||
type SRDict = { [_ in string]?: SRDict }; | ||
const SRDict: Runtype<SRDict> = Lazy(() => Record(String, SRDict)); | ||
const srDict: SRDict = {}; | ||
@@ -66,3 +63,5 @@ srDict['self'] = srDict; | ||
type Hand = { left: Hand } | { right: Hand }; | ||
const Hand: Runtype<Hand> = Lazy(() => Union(Record({ left: Hand }), Record({ right: Hand }))); | ||
const Hand: Runtype<Hand> = Lazy(() => | ||
Union(ObjectType({ left: Hand }), ObjectType({ right: Hand })), | ||
); | ||
const leftHand: Hand = { left: (null as any) as Hand }; | ||
@@ -73,3 +72,5 @@ const rightHand: Hand = { right: leftHand }; | ||
type Ambi = { left: Ambi } & { right: Ambi }; | ||
const Ambi: Runtype<Ambi> = Lazy(() => Intersect(Record({ left: Ambi }), Record({ right: Ambi }))); | ||
const Ambi: Runtype<Ambi> = Lazy(() => | ||
Intersect(ObjectType({ left: Ambi }), ObjectType({ right: Ambi })), | ||
); | ||
const ambi: Ambi = { left: (null as any) as Ambi, right: (null as any) as Ambi }; | ||
@@ -110,3 +111,3 @@ ambi.left = ambi; | ||
const runtypes = { | ||
const runtypes: { [key: string]: Runtype<unknown> } = { | ||
Unknown, | ||
@@ -116,3 +117,3 @@ Never, | ||
Null, | ||
Empty: Record({}), | ||
Empty: ObjectType({}), | ||
Void, | ||
@@ -132,5 +133,5 @@ Boolean, | ||
boolTuple, | ||
record1, | ||
object1, | ||
union1, | ||
Partial: RTPartial({ foo: String }).And(Record({ Boolean })), | ||
Partial: RTPartial({ foo: String }).And(ObjectType({ Boolean })), | ||
Function, | ||
@@ -148,5 +149,5 @@ Person, | ||
), | ||
Dictionary: Dictionary(String), | ||
NumberDictionary: Dictionary(String, 'number'), | ||
DictionaryOfArrays: Dictionary(Array(Boolean)), | ||
Record: Record(String, String), | ||
NumberRecord: Record(Number, String), | ||
RecordOfArrays: Record(String, Array(Boolean)), | ||
InstanceOfSomeClass: InstanceOf(SomeClass), | ||
@@ -170,6 +171,6 @@ InstanceOfSomeOtherClass: InstanceOf(SomeOtherClass), | ||
), | ||
DictionaryOfArraysOfSomeClass: Dictionary(Array(InstanceOf(SomeClass))), | ||
OptionalKey: Record({ foo: String, bar: Union(Number, Undefined) }), | ||
RecordOfArraysOfSomeClass: Record(String, Array(InstanceOf(SomeClass))), | ||
OptionalKey: ObjectType({ foo: String, bar: Union(Number, Undefined) }), | ||
ReadonlyNumberArray: Array(Number).asReadonly(), | ||
ReadonlyRecord: Record({ foo: Number, bar: String }).asReadonly(), | ||
ReadonlyRecord: ObjectType({ foo: Number, bar: String }).asReadonly(), | ||
Graph, | ||
@@ -181,3 +182,3 @@ SRDict, | ||
PartialPerson, | ||
ReadonlyPartial: Record({ foo: Number }) | ||
ReadonlyPartial: ObjectType({ foo: Number }) | ||
.asReadonly() | ||
@@ -194,3 +195,3 @@ .And(RTPartial({ bar: String }).asReadonly()), | ||
x!: 'blah'; | ||
} // Should not be recognized as a Dictionary | ||
} // Should not be recognized as a Record | ||
@@ -211,24 +212,24 @@ const testValues: { value: unknown; passes: RuntypeName[] }[] = [ | ||
{ value: [true, false, true], passes: ['boolArray', 'boolTuple', 'union1'] }, | ||
{ value: { Boolean: true, Number: 3 }, passes: ['record1', 'union1', 'Partial'] }, | ||
{ value: { Boolean: true }, passes: ['Partial'] }, | ||
{ value: { Boolean: true, foo: undefined }, passes: ['Partial'] }, | ||
{ value: { Boolean: true, foo: 'hello' }, passes: ['Partial', 'OptionalKey'] }, | ||
{ value: { Boolean: true, foo: 5 }, passes: ['ReadonlyPartial'] }, | ||
{ value: { Boolean: true, Number: 3 }, passes: ['object1', 'union1', 'Partial', 'Empty'] }, | ||
{ value: { Boolean: true }, passes: ['Partial', 'Empty'] }, | ||
{ value: { Boolean: true, foo: undefined }, passes: ['Partial', 'Empty'] }, | ||
{ value: { Boolean: true, foo: 'hello' }, passes: ['Partial', 'OptionalKey', 'Empty'] }, | ||
{ value: { Boolean: true, foo: 5 }, passes: ['ReadonlyPartial', 'Empty'] }, | ||
{ value: (x: number, y: string) => x + y.length, passes: ['Function'] }, | ||
{ value: { name: undefined, likes: [] }, passes: [] }, | ||
{ value: { name: 'Jimmy', likes: [{ name: undefined, likes: [] }] }, passes: [] }, | ||
{ value: { name: undefined, likes: [] }, passes: ['Empty'] }, | ||
{ value: { name: 'Jimmy', likes: [{ name: undefined, likes: [] }] }, passes: ['Empty'] }, | ||
{ | ||
value: { name: 'Jimmy', likes: [{ name: 'Peter', likes: [] }] }, | ||
passes: ['Person'], | ||
passes: ['Person', 'Empty'], | ||
}, | ||
{ value: { a: '1', b: '2' }, passes: ['Dictionary'] }, | ||
{ value: ['1', '2'], passes: ['ArrayString', 'NumberDictionary'] }, | ||
{ value: { a: '1', b: '2' }, passes: ['Record', 'Empty'] }, | ||
{ value: ['1', '2'], passes: ['ArrayString'] }, | ||
{ value: ['1', 2], passes: [] }, | ||
{ value: [{ name: 'Jimmy', likes: [{ name: 'Peter', likes: [] }] }], passes: ['ArrayPerson'] }, | ||
{ value: [{ name: null, likes: [] }], passes: [] }, | ||
{ value: { 1: '1', 2: '2' }, passes: ['Dictionary', 'NumberDictionary'] }, | ||
{ value: { a: [], b: [true, false] }, passes: ['DictionaryOfArrays'] }, | ||
{ value: new Foo(), passes: [] }, | ||
{ value: { 1: '1', 2: '2' }, passes: ['Record', 'NumberRecord', 'Empty'] }, | ||
{ value: { a: [], b: [true, false] }, passes: ['RecordOfArrays', 'Empty'] }, | ||
{ value: new Foo(), passes: ['Empty'] }, | ||
{ value: [1, 2, 4], passes: ['ArrayNumber', 'ReadonlyNumberArray'] }, | ||
{ value: { Boolean: true, Number: '5' }, passes: ['Partial'] }, | ||
{ value: { Boolean: true, Number: '5' }, passes: ['Partial', 'Empty'] }, | ||
{ | ||
@@ -246,2 +247,3 @@ value: [1, 2, 3, 4], | ||
'GuardChangeTypeAndName', | ||
'Empty', | ||
], | ||
@@ -257,16 +259,17 @@ }, | ||
'GuardChangeTypeAndName', | ||
'Empty', | ||
], | ||
}, | ||
{ value: { xxx: [new SomeClass(55)] }, passes: ['DictionaryOfArraysOfSomeClass'] }, | ||
{ value: { foo: 'hello' }, passes: ['OptionalKey', 'Dictionary'] }, | ||
{ value: { foo: 'hello', bar: undefined }, passes: ['OptionalKey'] }, | ||
{ value: { foo: 4, bar: 'baz' }, passes: ['ReadonlyRecord', 'ReadonlyPartial'] }, | ||
{ value: narcissist, passes: ['Person'] }, | ||
{ value: { xxx: [new SomeClass(55)] }, passes: ['RecordOfArraysOfSomeClass', 'Empty'] }, | ||
{ value: { foo: 'hello' }, passes: ['OptionalKey', 'Record', 'Empty'] }, | ||
{ value: { foo: 'hello', bar: undefined }, passes: ['OptionalKey', 'Empty'] }, | ||
{ value: { foo: 4, bar: 'baz' }, passes: ['ReadonlyRecord', 'ReadonlyPartial', 'Empty'] }, | ||
{ value: narcissist, passes: ['Person', 'Empty'] }, | ||
{ value: [narcissist, narcissist], passes: ['ArrayPerson'] }, | ||
{ value: barbell, passes: ['Graph'] }, | ||
{ value: nodeA, passes: ['Graph', 'BarbellBall'] }, | ||
{ value: srDict, passes: ['SRDict'] }, | ||
{ value: leftHand, passes: ['Hand', 'SRDict'] }, | ||
{ value: ambi, passes: ['Ambi', 'Hand', 'SRDict'] }, | ||
{ value: partialNarcissus, passes: ['PartialPerson'] }, | ||
{ value: srDict, passes: ['SRDict', 'Empty'] }, | ||
{ value: leftHand, passes: ['Hand', 'SRDict', 'Empty'] }, | ||
{ value: ambi, passes: ['Ambi', 'Hand', 'SRDict', 'Empty'] }, | ||
{ value: partialNarcissus, passes: ['PartialPerson', 'Empty'] }, | ||
]; | ||
@@ -290,17 +293,14 @@ | ||
value === undefined ? 'undefined' : JSON.stringify(value, getCircularReplacer()); | ||
describe(`${valueName}`, () => { | ||
const shouldPass: { [_ in RuntypeName]?: boolean } = {}; | ||
const shouldPass: { [_ in RuntypeName]?: boolean } = {}; | ||
shouldPass.Unknown = true; | ||
shouldPass.Void = true; | ||
shouldPass.Unknown = true; | ||
shouldPass.Void = true; | ||
if (value !== undefined && value !== null) shouldPass.Empty = true; | ||
for (const name of passes) shouldPass[name] = true; | ||
for (const name of passes) shouldPass[name] = true; | ||
describe(`${valueName} - ${Object.keys(shouldPass).join(', ')}`, () => { | ||
for (const name of runtypeNames) { | ||
if (shouldPass[name]) { | ||
it(` : ${name}`, () => assertAccepts(value, runtypes[name])); | ||
it(`should be valid for ${name}`, () => assertAccepts(value, runtypes[name])); | ||
} else { | ||
it(`~: ${name}`, () => assertRejects(value, runtypes[name])); | ||
it(`should NOT be valid for ${name}`, () => assertRejects(value, runtypes[name])); | ||
} | ||
@@ -314,5 +314,5 @@ } | ||
const f = () => 3; | ||
expect(Contract(Number).enforce(f)()).toBe(3); | ||
expect(Contract([], Number).enforce(f)()).toBe(3); | ||
try { | ||
Contract(String).enforce(f as any)(); | ||
Contract([], String).enforce(f as any)(); | ||
fail('contract was violated but no exception was thrown'); | ||
@@ -327,5 +327,5 @@ } catch (exception) { | ||
const f = (x: string) => x.length; | ||
expect(Contract(String, Number).enforce(f)('hel')).toBe(3); | ||
expect(Contract([String], Number).enforce(f)('hel')).toBe(3); | ||
try { | ||
(Contract(String, Number).enforce(f) as any)(3); | ||
(Contract([String], Number).enforce(f) as any)(3); | ||
fail('contract was violated but no exception was thrown'); | ||
@@ -340,5 +340,5 @@ } catch (exception) { | ||
const f = (x: string, y: boolean) => (y ? x.length : 4); | ||
expect(Contract(String, Boolean, Number).enforce(f)('hello', false)).toBe(4); | ||
expect(Contract([String, Boolean], Number).enforce(f)('hello', false)).toBe(4); | ||
try { | ||
(Contract(String, Boolean, Number).enforce(f) as any)('hello'); | ||
(Contract([String, Boolean], Number).enforce(f) as any)('hello'); | ||
fail('contract was violated but no exception was thrown'); | ||
@@ -373,3 +373,3 @@ } catch (exception) { | ||
[0, { name: 0 }], | ||
Tuple(Number, Record({ name: String })), | ||
Tuple(Number, ObjectType({ name: String })), | ||
'Expected string, but was number in [1].name', | ||
@@ -391,3 +391,3 @@ '[1].name', | ||
[{ name: 'Foo' }, { name: false }], | ||
Array(Record({ name: String })), | ||
Array(ObjectType({ name: String })), | ||
'Expected string, but was boolean in [1].name', | ||
@@ -401,3 +401,3 @@ '[1].name', | ||
[{ name: 'Foo' }, null], | ||
Array(Record({ name: String })), | ||
Array(ObjectType({ name: String })), | ||
'Expected { name: string; }, but was null in [1]', | ||
@@ -420,3 +420,3 @@ '[1]', | ||
[{ name: 'Foo' }, { name: false }], | ||
Array(Record({ name: String })).asReadonly(), | ||
Array(ObjectType({ name: String })).asReadonly(), | ||
'Expected string, but was boolean in [1].name', | ||
@@ -430,3 +430,3 @@ '[1].name', | ||
[{ name: 'Foo' }, null], | ||
Array(Record({ name: String })).asReadonly(), | ||
Array(ObjectType({ name: String })).asReadonly(), | ||
'Expected { name: string; }, but was null in [1]', | ||
@@ -438,3 +438,3 @@ '[1]', | ||
it('dictionary', () => { | ||
assertThrows(null, Dictionary(String), 'Expected { [_: string]: string }, but was null'); | ||
assertThrows(null, Record(String, String), 'Expected { [_: string]: string }, but was null'); | ||
}); | ||
@@ -445,3 +445,3 @@ | ||
undefined, | ||
Dictionary(Record({ name: String })), | ||
Record(String, ObjectType({ name: String })), | ||
'Expected { [_: string]: { name: string; } }, but was undefined', | ||
@@ -451,3 +451,3 @@ ); | ||
1, | ||
Dictionary(Record({ name: String })), | ||
Record(String, ObjectType({ name: String })), | ||
'Expected { [_: string]: { name: string; } }, but was number', | ||
@@ -460,3 +460,3 @@ ); | ||
{ foo: { name: false } }, | ||
Dictionary(Record({ name: String })), | ||
Record(String, ObjectType({ name: String })), | ||
'Expected string, but was boolean in foo.name', | ||
@@ -470,3 +470,3 @@ 'foo.name', | ||
{ foo: 'bar', test: true }, | ||
Dictionary(String), | ||
Record(String, String), | ||
'Expected string, but was boolean in test', | ||
@@ -480,3 +480,3 @@ 'test', | ||
{ 1: 'bar', 2: 20 }, | ||
Dictionary(String, 'number'), | ||
Record(Number, String), | ||
'Expected string, but was number in 2', | ||
@@ -487,6 +487,6 @@ '2', | ||
it('record', () => { | ||
it('object', () => { | ||
assertThrows( | ||
{ name: 'Jack', age: '10' }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
@@ -500,6 +500,6 @@ age: Number, | ||
it('record missing keys', () => { | ||
it('object missing keys', () => { | ||
assertThrows( | ||
{ name: 'Jack' }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
@@ -513,9 +513,9 @@ age: Number, | ||
it('record complex', () => { | ||
it('object complex', () => { | ||
assertThrows( | ||
{ name: 'Jack', age: 10, likes: [{ title: false }] }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
age: Number, | ||
likes: Array(Record({ title: String })), | ||
likes: Array(ObjectType({ title: String })), | ||
}), | ||
@@ -527,6 +527,6 @@ 'Expected string, but was boolean in likes.[0].title', | ||
it('readonly record', () => { | ||
it('readonly object', () => { | ||
assertThrows( | ||
{ name: 'Jack', age: '10' }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
@@ -540,6 +540,6 @@ age: Number, | ||
it('readonly record missing keys', () => { | ||
it('readonly object missing keys', () => { | ||
assertThrows( | ||
{ name: 'Jack' }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
@@ -553,9 +553,9 @@ age: Number, | ||
it('readonly record complex', () => { | ||
it('readonly object complex', () => { | ||
assertThrows( | ||
{ name: 'Jack', age: 10, likes: [{ title: false }] }, | ||
Record({ | ||
ObjectType({ | ||
name: String, | ||
age: Number, | ||
likes: Array(Record({ title: String }).asReadonly()), | ||
likes: Array(ObjectType({ title: String }).asReadonly()), | ||
}).asReadonly(), | ||
@@ -585,3 +585,3 @@ 'Expected string, but was boolean in likes.[0].title', | ||
age: Number, | ||
likes: Array(Record({ title: String })), | ||
likes: Array(ObjectType({ title: String })), | ||
}), | ||
@@ -676,16 +676,16 @@ 'Expected string, but was number in likes.[0].title', | ||
it('string dictionary', () => { | ||
const Rec = Dictionary(Unknown); | ||
expectLiteralField(Rec, 'tag', 'dictionary'); | ||
expectLiteralField(Rec, 'key', 'string'); | ||
const Rec = Record(String, Unknown); | ||
expectLiteralField(Rec, 'tag', 'record'); | ||
expectLiteralField(Rec.key, 'tag', 'string'); | ||
}); | ||
it('number dictionary', () => { | ||
const Rec = Dictionary(Unknown, 'number'); | ||
expectLiteralField(Rec, 'tag', 'dictionary'); | ||
expectLiteralField(Rec, 'key', 'number'); | ||
const Rec = Record(Number, Unknown); | ||
expectLiteralField(Rec, 'tag', 'record'); | ||
expectLiteralField(Rec.key, 'tag', 'number'); | ||
}); | ||
it('record', () => { | ||
const Rec = Record({ x: Number, y: Literal(3) }); | ||
expectLiteralField(Rec, 'tag', 'record'); | ||
it('object', () => { | ||
const Rec = ObjectType({ x: Number, y: Literal(3) }); | ||
expectLiteralField(Rec, 'tag', 'object'); | ||
expectLiteralField(Rec.fields.x, 'tag', 'number'); | ||
@@ -697,5 +697,5 @@ expectLiteralField(Rec.fields.y, 'tag', 'literal'); | ||
it('record (asReadonly)', () => { | ||
const Rec = Record({ x: Number, y: Literal(3) }).asReadonly(); | ||
expectLiteralField(Rec, 'tag', 'record'); | ||
it('object (asReadonly)', () => { | ||
const Rec = ObjectType({ x: Number, y: Literal(3) }).asReadonly(); | ||
expectLiteralField(Rec, 'tag', 'object'); | ||
expectLiteralField(Rec.fields.x, 'tag', 'number'); | ||
@@ -709,3 +709,3 @@ expectLiteralField(Rec.fields.y, 'tag', 'literal'); | ||
const Opt = RTPartial({ x: Number, y: Literal(3) }); | ||
expectLiteralField(Opt, 'tag', 'record'); | ||
expectLiteralField(Opt, 'tag', 'object'); | ||
expectLiteralField(Opt.fields.x, 'tag', 'number'); | ||
@@ -736,4 +736,5 @@ expectLiteralField(Opt.fields.y, 'tag', 'literal'); | ||
const L = Lazy(() => X); | ||
expectLiteralField(L, 'tag', 'literal'); | ||
expectLiteralField(L, 'value', 'x'); | ||
expectLiteralField(L, 'tag', 'lazy'); | ||
expectLiteralField(L.underlying(), 'tag', 'literal'); | ||
expectLiteralField(L.underlying(), 'value', 'x'); | ||
}); | ||
@@ -751,3 +752,3 @@ | ||
expectLiteralField(InstanceOf(Test), 'tag', 'instanceof'); | ||
expectLiteralField(Dictionary(Array(InstanceOf(Test))), 'tag', 'dictionary'); | ||
expectLiteralField(Record(String, Array(InstanceOf(Test))), 'tag', 'record'); | ||
}); | ||
@@ -768,3 +769,3 @@ | ||
if (C.guard(value)) { | ||
if (C.test(value)) { | ||
return value; | ||
@@ -795,17 +796,18 @@ } else { | ||
| Literal<boolean | number | string> | ||
| Array<Reflect, false> | ||
| Array<Reflect, true> | ||
| Record<{ [_ in string]: Reflect }, false> | ||
| Record<{ [_ in string]: Reflect }, true> | ||
| RTPartial<{ [_ in string]: Reflect }, false> | ||
| RTPartial<{ [_ in string]: Reflect }, true> | ||
| Tuple2<Reflect, Reflect> | ||
| Union2<Reflect, Reflect> | ||
| Intersect2<Reflect, Reflect> | ||
| Array<String | Number> | ||
| ReadonlyArray<String | Number> | ||
| ObjectType<{ [_ in string]: String | Number }, false> | ||
| ObjectType<{ [_ in string]: String | Number }, true> | ||
| RTPartial<{ [_ in string]: String | Number }, false> | ||
| RTPartial<{ [_ in string]: String | Number }, true> | ||
| Tuple<[String, String | Number]> | ||
| Union<[String, String | Number]> | ||
| Intersect<[String | Number, String | Number]> | ||
| Function | ||
| Constraint<Reflect, any, any> | ||
| Constraint<String | Number, any, any> | ||
| InstanceOf<Constructor<never>> | ||
| Brand<string, Reflect>, | ||
): Reflect => { | ||
const check = <A>(X: Runtype<A>): A => X.check({}); | ||
| Brand<string, String | Number>, | ||
) => { | ||
const check = <A>(X: Runtype<A>): A => X.parse({}); | ||
switch (X.tag) { | ||
@@ -834,6 +836,10 @@ case 'unknown': | ||
case 'array': | ||
check<ReadonlyArray<Static<typeof X.element>>>(X); | ||
check<readonly Static<typeof X.element>[]>(X); | ||
break; | ||
case 'record': | ||
check<{ readonly [K in keyof typeof X.fields]: Static<typeof X.fields[K]> }>(X); | ||
case 'object': | ||
if (X.isPartial) { | ||
check<{ readonly [K in keyof typeof X.fields]?: Static<typeof X.fields[K]> }>(X); | ||
} else { | ||
check<{ readonly [K in keyof typeof X.fields]: Static<typeof X.fields[K]> }>(X); | ||
} | ||
break; | ||
@@ -862,4 +868,2 @@ case 'tuple': | ||
} | ||
return X; | ||
}; | ||
@@ -872,3 +876,3 @@ | ||
function assertAccepts<A>(value: unknown, runtype: Runtype<A>) { | ||
const result = runtype.validate(value); | ||
const result = runtype.safeParse(value); | ||
if (result.success === false) fail(result.message); | ||
@@ -878,3 +882,3 @@ } | ||
function assertRejects<A>(value: unknown, runtype: Runtype<A>) { | ||
const result = runtype.validate(value); | ||
const result = runtype.safeParse(value); | ||
if (result.success === true) fail('value passed validation even though it was not expected to'); | ||
@@ -885,3 +889,3 @@ } | ||
try { | ||
runtype.check(value); | ||
runtype.parse(value); | ||
fail('value passed validation even though it was not expected to'); | ||
@@ -888,0 +892,0 @@ } catch (exception) { |
@@ -1,27 +0,34 @@ | ||
export { Runtype, Static } from './runtype'; | ||
export * from './reflect'; | ||
export * from './result'; | ||
export * from './contract'; | ||
export * from './asynccontract'; | ||
export * from './match'; | ||
export * from './errors'; | ||
export * from './types/unknown'; | ||
export * from './types/never'; | ||
export * from './types/void'; | ||
export { Literal, Undefined, Null } from './types/literal'; | ||
export * from './types/boolean'; | ||
export * from './types/number'; | ||
export * from './types/string'; | ||
export * from './types/symbol'; | ||
export * from './types/array'; | ||
export * from './types/tuple'; | ||
export * from './types/record'; | ||
export * from './types/dictionary'; | ||
export * from './types/union'; | ||
export * from './types/intersect'; | ||
export * from './types/function'; | ||
export { AsyncContract } from './asynccontract'; | ||
export { Contract } from './contract'; | ||
export { assertType } from './assertType'; | ||
export type { Runtype, Codec, Static } from './runtype'; | ||
export type { Success, Failure, Result } from './result'; | ||
export { ValidationError } from './errors'; | ||
// TODO: should we export StaticIntersect, StaticTuple, StaticUnion etc. | ||
export { Array, ReadonlyArray } from './types/array'; | ||
export { Boolean } from './types/boolean'; | ||
export type { ConstraintCheck } from './types/constraint'; | ||
export { Constraint, Guard } from './types/constraint'; | ||
export { Dictionary } from './types/dictionary'; | ||
export { Function } from './types/function'; | ||
export { InstanceOf } from './types/instanceof'; | ||
export * from './types/lazy'; | ||
export * from './types/constraint'; | ||
export { Intersect } from './types/intersect'; | ||
export { Lazy } from './types/lazy'; | ||
export type { LiteralValue } from './types/literal'; | ||
export { Literal, Null, Undefined } from './types/literal'; | ||
export { Never } from './types/never'; | ||
export { Number } from './types/number'; | ||
export { Object, Partial } from './types/Object'; | ||
export { Record } from './types/Record'; | ||
export { String } from './types/string'; | ||
export { Symbol } from './types/symbol'; | ||
export { Tuple } from './types/tuple'; | ||
export { Union } from './types/union'; | ||
export { Unknown } from './types/unknown'; | ||
/** | ||
* @deprecated use Unknown | ||
*/ | ||
export { Void } from './types/void'; | ||
export { Brand } from './types/brand'; | ||
export * from './decorator'; | ||
export { ParsedValue } from './types/ParsedValue'; |
@@ -1,46 +0,100 @@ | ||
import { | ||
Result, | ||
Union, | ||
Union2, | ||
Intersect, | ||
Intersect2, | ||
Constraint, | ||
ConstraintCheck, | ||
Brand, | ||
} from './index'; | ||
import { Reflect } from './reflect'; | ||
import { Result, Union, Intersect, Constraint, ConstraintCheck, Brand, Failure } from './index'; | ||
import show from './show'; | ||
import { ValidationError } from './errors'; | ||
import { ParsedValue, ParsedValueConfig } from './types/ParsedValue'; | ||
export type InnerValidateHelper = <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>; | ||
declare const internalSymbol: unique symbol; | ||
const internal: typeof internalSymbol = ('__internal__' as unknown) as typeof internalSymbol; | ||
export type ResultWithCycle<T> = (Result<T> & { cycle?: false }) | Cycle<T>; | ||
export interface InternalValidation<TParsed> { | ||
validate( | ||
x: any, | ||
innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Result<T>, | ||
innerValidateToPlaceholder: <T>(runtype: RuntypeBase<T>, value: unknown) => ResultWithCycle<T>, | ||
): ResultWithCycle<TParsed>; | ||
test?: ( | ||
x: any, | ||
innerValidate: <T>(runtype: RuntypeBase<T>, value: unknown) => Failure | undefined, | ||
) => Failure | undefined; | ||
serialize?: ( | ||
// any is used here to ensure TypeScript still treats RuntypeBase as | ||
// covariant. | ||
x: any, | ||
innerSerialize: (runtype: RuntypeBase, value: unknown) => Result<any>, | ||
innerSerializeToPlaceholder: (runtype: RuntypeBase, value: unknown) => ResultWithCycle<any>, | ||
) => ResultWithCycle<any>; | ||
} | ||
/** | ||
* A runtype determines at runtime whether a value conforms to a type specification. | ||
*/ | ||
export interface Runtype<A = unknown> { | ||
export interface RuntypeBase<TParsed = unknown> { | ||
readonly tag: string; | ||
/** | ||
* Verifies that a value conforms to this runtype. When given a value that does | ||
* not conform to the runtype, throws an exception. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
assert(x: any): asserts x is A; | ||
assert(x: any): asserts x is TParsed; | ||
/** | ||
* Verifies that a value conforms to this runtype. If so, returns the same value, | ||
* statically typed. Otherwise throws an exception. | ||
* A type guard for this runtype. | ||
*/ | ||
check(x: any): A; | ||
test(x: any): x is TParsed; | ||
/** | ||
* Validates that a value conforms to this type, and returns a result indicating | ||
* success or failure (does not throw). | ||
* @deprecated use Runtype.test | ||
*/ | ||
validate(x: any): Result<A>; | ||
guard(x: any): x is TParsed; | ||
/** | ||
* A type guard for this runtype. | ||
* Validates the value conforms to this type, and performs | ||
* the `parse` action for any `ParsedValue` types. | ||
* | ||
* If the value is valid, it returns the parsed value, | ||
* otherwise it throws a ValidationError. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
guard(x: any): x is A; | ||
parse(x: any): TParsed; | ||
/** | ||
* @deprecated use Runtype.parse | ||
*/ | ||
check(x: any): TParsed; | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `parse` action for any `ParsedValue` types. | ||
* | ||
* Returns a `Result`, constaining the parsed value or | ||
* error message. Does not throw! | ||
*/ | ||
safeParse(x: any): Result<TParsed>; | ||
/** | ||
* @deprecated use Runtype.safeParse | ||
*/ | ||
validate(x: any): Result<TParsed>; | ||
show?: (ctx: { | ||
needsParens: boolean; | ||
parenthesize: (str: string) => string; | ||
showChild: (rt: RuntypeBase, needsParens: boolean) => string; | ||
}) => string; | ||
[internal]: InternalValidation<TParsed>; | ||
} | ||
/** | ||
* A runtype determines at runtime whether a value conforms to a type specification. | ||
*/ | ||
export interface Runtype<TParsed> extends RuntypeBase<TParsed> { | ||
/** | ||
* Union this Runtype with another. | ||
*/ | ||
Or<B extends Runtype>(B: B): Union2<this, B>; | ||
Or<B extends RuntypeBase>(B: B): Union<[this, B]>; | ||
@@ -50,3 +104,3 @@ /** | ||
*/ | ||
And<B extends Runtype>(B: B): Intersect2<this, B>; | ||
And<B extends RuntypeBase>(B: B): Intersect<[this, B]>; | ||
@@ -74,7 +128,7 @@ /** | ||
* via a type guard function. The static type of the runtype is inferred from | ||
* the type of the guard function. | ||
* the type of the test function. | ||
* | ||
* @template T - Typically inferred from the return type of the type guard | ||
* function, so usually not needed to specify manually. | ||
* @param {(x: Static<this>) => x is T} guard - Type guard function (see | ||
* @param {(x: Static<this>) => x is T} test - Type test function (see | ||
* https://www.typescriptlang.org/docs/handbook/advanced-types.html#user-defined-type-guards) | ||
@@ -88,3 +142,3 @@ * | ||
withGuard<T extends Static<this>, K = unknown>( | ||
guard: (x: Static<this>) => x is T, | ||
test: (x: Static<this>) => x is T, | ||
options?: { name?: string; args?: K }, | ||
@@ -99,106 +153,388 @@ ): Constraint<this, T, K>; | ||
/** | ||
* Convert this to a Reflect, capable of introspecting the structure of the type. | ||
* Apply conversion functions when parsing/serializing this value | ||
*/ | ||
reflect: Reflect; | ||
withParser<TParsed>(value: ParsedValueConfig<this, TParsed>): ParsedValue<this, TParsed>; | ||
} | ||
/* @internal */ _falseWitness: A; | ||
export interface Codec<TParsed> extends Runtype<TParsed> { | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `serialize` action for any `ParsedValue` types. | ||
* | ||
* If the value is valid, and the type supports serialize, | ||
* it returns the serialized value, otherwise it throws a | ||
* ValidationError. | ||
* | ||
* @throws ValidationError | ||
*/ | ||
serialize: (x: TParsed) => unknown; | ||
/** | ||
* Validates the value conforms to this type, and performs | ||
* the `serialize` action for any `ParsedValue` types. | ||
* | ||
* Returns a `Result`, constaining the serialized value or | ||
* error message. Does not throw! | ||
*/ | ||
safeSerialize: (x: TParsed) => Result<unknown>; | ||
} | ||
/** | ||
* Obtains the static type associated with a Runtype. | ||
*/ | ||
export type Static<A extends Runtype> = A['_falseWitness']; | ||
export type Static<A extends RuntypeBase<any>> = A extends RuntypeBase<infer T> ? T : unknown; | ||
export function create<A extends Runtype>( | ||
validate: (x: any, visited: VisitedState) => Result<Static<A>>, | ||
A: any, | ||
): A { | ||
A.check = check; | ||
A.assert = check; | ||
A._innerValidate = (value: any, visited: VisitedState) => { | ||
if (visited.has(value, A)) return { success: true, value }; | ||
return validate(value, visited); | ||
export function create<TConfig extends Codec<any>>( | ||
internalImplementation: | ||
| InternalValidation<Static<TConfig>> | ||
| InternalValidation<Static<TConfig>>['validate'], | ||
config: Omit< | ||
TConfig, | ||
| 'assert' | ||
| 'check' | ||
| 'test' | ||
| 'guard' | ||
| 'parse' | ||
| 'check' | ||
| 'safeParse' | ||
| 'validate' | ||
| 'serialize' | ||
| 'safeSerialize' | ||
| 'Or' | ||
| 'And' | ||
| 'withConstraint' | ||
| 'withGuard' | ||
| 'withBrand' | ||
| 'withParser' | ||
| typeof internal | ||
>, | ||
): TConfig { | ||
const A: Codec<Static<TConfig>> = { | ||
...config, | ||
assert, | ||
parse, | ||
check: parse, | ||
safeParse, | ||
validate: safeParse, | ||
test, | ||
guard: test, | ||
serialize, | ||
safeSerialize, | ||
Or, | ||
And, | ||
withConstraint, | ||
withGuard, | ||
withBrand, | ||
withParser, | ||
toString: () => `Runtype<${show(A)}>`, | ||
[internal]: | ||
typeof internalImplementation === 'function' | ||
? { | ||
validate: internalImplementation, | ||
} | ||
: internalImplementation, | ||
}; | ||
A.validate = (value: any) => A._innerValidate(value, VisitedState()); | ||
A.guard = guard; | ||
A.Or = Or; | ||
A.And = And; | ||
A.withConstraint = withConstraint; | ||
A.withGuard = withGuard; | ||
A.withBrand = withBrand; | ||
A.reflect = A; | ||
A.toString = () => `Runtype<${show(A)}>`; | ||
return A; | ||
return (A as unknown) as TConfig; | ||
function check(x: any) { | ||
const validated = A.validate(x); | ||
if (validated.success) { | ||
return validated.value; | ||
function safeParse(x: any) { | ||
return innerValidate(A, x, createVisitedState()); | ||
} | ||
function safeSerialize(x: any) { | ||
return innerSerialize(A, x, createVisitedState()); | ||
} | ||
function parse(x: any) { | ||
const validated = safeParse(x); | ||
if (!validated.success) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
throw new ValidationError(validated.message, validated.key); | ||
return validated.value; | ||
} | ||
function serialize(x: any) { | ||
const validated = safeSerialize(x); | ||
if (!validated.success) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
return validated.value; | ||
} | ||
function guard(x: any): x is A { | ||
return A.validate(x).success; | ||
function assert(x: any): asserts x is Static<TConfig> { | ||
const validated = innerGuard(A, x, createGuardVisitedState()); | ||
if (validated) { | ||
throw new ValidationError(validated.message, validated.key); | ||
} | ||
} | ||
function test(x: any): x is Static<TConfig> { | ||
const validated = innerGuard(A, x, createGuardVisitedState()); | ||
return validated === undefined; | ||
} | ||
function Or<B extends Runtype>(B: B): Union2<A, B> { | ||
function Or<B extends RuntypeBase>(B: B): Union<[Codec<Static<TConfig>>, B]> { | ||
return Union(A, B); | ||
} | ||
function And<B extends Runtype>(B: B): Intersect2<A, B> { | ||
function And<B extends RuntypeBase>(B: B): Intersect<[Codec<Static<TConfig>>, B]> { | ||
return Intersect(A, B); | ||
} | ||
function withConstraint<T extends Static<A>, K = unknown>( | ||
constraint: ConstraintCheck<A>, | ||
function withConstraint<T extends Static<TConfig>, K = unknown>( | ||
constraint: ConstraintCheck<Codec<Static<TConfig>>>, | ||
options?: { name?: string; args?: K }, | ||
): Constraint<A, T, K> { | ||
return Constraint<A, T, K>(A, constraint, options); | ||
): Constraint<Codec<Static<TConfig>>, T, K> { | ||
return Constraint<Codec<Static<TConfig>>, T, K>(A, constraint, options); | ||
} | ||
function withGuard<T extends Static<A>, K = unknown>( | ||
guard: (x: Static<A>) => x is T, | ||
function withGuard<T extends Static<TConfig>, K = unknown>( | ||
test: (x: Static<TConfig>) => x is T, | ||
options?: { name?: string; args?: K }, | ||
): Constraint<A, T, K> { | ||
return Constraint<A, T, K>(A, guard, options); | ||
): Constraint<Codec<Static<TConfig>>, T, K> { | ||
return Constraint<Codec<Static<TConfig>>, T, K>(A, test, options); | ||
} | ||
function withBrand<B extends string>(B: B): Brand<B, A> { | ||
return Brand(B, A); | ||
function withBrand<B extends string>(B: B): Brand<B, Codec<Static<TConfig>>> { | ||
return Brand<B, Codec<Static<TConfig>>>(B, A); | ||
} | ||
} | ||
export function innerValidate<A extends Runtype>( | ||
targetType: A, | ||
value: any, | ||
visited: VisitedState, | ||
): Result<Static<A>> { | ||
return (targetType as any)._innerValidate(value, visited); | ||
function withParser<TParsed>( | ||
config: ParsedValueConfig<Codec<Static<TConfig>>, TParsed>, | ||
): ParsedValue<Codec<Static<TConfig>>, TParsed> { | ||
return ParsedValue(A as any, config); | ||
} | ||
} | ||
type VisitedState = { | ||
has: (candidate: object, type: Runtype) => boolean; | ||
export type Cycle<T> = { | ||
success: true; | ||
cycle: true; | ||
placeholder: Partial<T>; | ||
unwrap: () => Result<T>; | ||
}; | ||
function VisitedState(): VisitedState { | ||
const members: WeakMap<object, WeakMap<Runtype, true>> = new WeakMap(); | ||
const add = (candidate: object, type: Runtype) => { | ||
if (candidate === null || !(typeof candidate === 'object')) return; | ||
const typeSet = members.get(candidate); | ||
members.set( | ||
candidate, | ||
typeSet ? typeSet.set(type, true) : (new WeakMap() as WeakMap<Runtype, true>).set(type, true), | ||
); | ||
function attemptMixin<T>(placeholder: any, value: T): Result<T> { | ||
if (placeholder === value) { | ||
return { success: true, value }; | ||
} | ||
if (Array.isArray(placeholder) && Array.isArray(value)) { | ||
placeholder.splice(0, placeholder.length, ...value); | ||
return { success: true, value: placeholder as any }; | ||
} | ||
if ( | ||
placeholder && | ||
typeof placeholder === 'object' && | ||
!Array.isArray(placeholder) && | ||
value && | ||
typeof value === 'object' && | ||
!Array.isArray(value) | ||
) { | ||
Object.assign(placeholder, value); | ||
return { success: true, value: placeholder }; | ||
} | ||
return { | ||
success: false, | ||
message: `Cannot convert a value of type "${ | ||
Array.isArray(placeholder) ? 'Array' : typeof placeholder | ||
}" into a value of type "${ | ||
value === null ? 'null' : Array.isArray(value) ? 'Array' : typeof value | ||
}" when it contains cycles.`, | ||
}; | ||
} | ||
const has = (candidate: object, type: Runtype) => { | ||
const typeSet = members.get(candidate); | ||
const value = (typeSet && typeSet.get(type)) || false; | ||
add(candidate, type); | ||
return value; | ||
export function createValidationPlaceholder<T>( | ||
placeholder: T, | ||
fn: (placeholder: T) => Failure | undefined, | ||
): Cycle<T> { | ||
return innerMapValidationPlaceholder( | ||
placeholder, | ||
() => fn(placeholder) || { success: true, value: placeholder }, | ||
); | ||
} | ||
export function mapValidationPlaceholder<T, S>( | ||
source: ResultWithCycle<T>, | ||
fn: (placeholder: T) => Result<S>, | ||
extraGuard?: RuntypeBase<S>, | ||
): ResultWithCycle<S> { | ||
if (!source.success) return source; | ||
if (!source.cycle) { | ||
const result = fn(source.value); | ||
return ( | ||
(result.success && | ||
extraGuard && | ||
innerGuard(extraGuard, result.value, createGuardVisitedState())) || | ||
result | ||
); | ||
} | ||
return innerMapValidationPlaceholder( | ||
Array.isArray(source.placeholder) ? [...source.placeholder] : { ...source.placeholder }, | ||
() => source.unwrap(), | ||
fn, | ||
extraGuard, | ||
); | ||
} | ||
function innerMapValidationPlaceholder( | ||
placeholder: any, | ||
populate: () => Result<any>, | ||
fn?: (placeholder: any) => Result<any>, | ||
extraGuard?: RuntypeBase<any>, | ||
): Cycle<any> { | ||
let hasCycle = false; | ||
let cache: Result<any> | undefined; | ||
const cycle: Cycle<any> = { | ||
success: true, | ||
cycle: true, | ||
placeholder, | ||
unwrap: () => { | ||
if (cache) { | ||
hasCycle = true; | ||
return cache; | ||
} | ||
cache = { success: true, value: placeholder }; | ||
const sourceResult = populate(); | ||
const result = sourceResult.success && fn ? fn(sourceResult.value) : sourceResult; | ||
if (!result.success) return result; | ||
if (hasCycle) { | ||
const unwrapResult = attemptMixin(cache.value, result.value); | ||
const guardFailure = | ||
unwrapResult.success && | ||
extraGuard && | ||
innerGuard(extraGuard, unwrapResult.value, createGuardVisitedState()); | ||
cache = guardFailure || unwrapResult; | ||
} else { | ||
const guardFailure = | ||
extraGuard && innerGuard(extraGuard, result.value, createGuardVisitedState()); | ||
cache = guardFailure || result; | ||
} | ||
if (cache.success) { | ||
cycle.placeholder = cache.value; | ||
} | ||
return cache; | ||
}, | ||
}; | ||
return cycle; | ||
} | ||
return { has }; | ||
declare const OpaqueVisitedState: unique symbol; | ||
export type OpaqueVisitedState = typeof OpaqueVisitedState; | ||
type VisitedState = Map<RuntypeBase<unknown>, Map<any, Cycle<any>>>; | ||
function unwrapVisitedState(o: OpaqueVisitedState): VisitedState { | ||
return o as any; | ||
} | ||
function wrapVisitedState(o: VisitedState): OpaqueVisitedState { | ||
return o as any; | ||
} | ||
export function createVisitedState(): OpaqueVisitedState { | ||
return wrapVisitedState(new Map()); | ||
} | ||
declare const OpaqueGuardVisitedState: unique symbol; | ||
export type OpaqueGuardVisitedState = typeof OpaqueGuardVisitedState; | ||
type GuardVisitedState = Map<RuntypeBase<unknown>, Set<any>>; | ||
function unwrapGuardVisitedState(o: OpaqueGuardVisitedState): GuardVisitedState { | ||
return o as any; | ||
} | ||
function wrapGuardVisitedState(o: GuardVisitedState): OpaqueGuardVisitedState { | ||
return o as any; | ||
} | ||
export function createGuardVisitedState(): OpaqueGuardVisitedState { | ||
return wrapGuardVisitedState(new Map()); | ||
} | ||
export function innerValidate<T>( | ||
targetType: RuntypeBase<T>, | ||
value: any, | ||
$visited: OpaqueVisitedState, | ||
): Result<T> { | ||
const result = innerValidateToPlaceholder(targetType, value, $visited); | ||
if (result.cycle) { | ||
return result.unwrap(); | ||
} | ||
return result; | ||
} | ||
function innerValidateToPlaceholder<T>( | ||
targetType: RuntypeBase<T>, | ||
value: any, | ||
$visited: OpaqueVisitedState, | ||
): ResultWithCycle<T> { | ||
const visited = unwrapVisitedState($visited); | ||
const validator = targetType[internal]; | ||
const cached = visited.get(targetType)?.get(value); | ||
if (cached !== undefined) { | ||
return cached; | ||
} | ||
const result = validator.validate( | ||
value, | ||
(t, v) => innerValidate(t, v, $visited), | ||
(t, v) => innerValidateToPlaceholder(t, v, $visited), | ||
); | ||
if (result.cycle) { | ||
visited.set(targetType, (visited.get(targetType) || new Map()).set(value, result)); | ||
return result; | ||
} | ||
return result; | ||
} | ||
export function innerSerialize<T>( | ||
targetType: RuntypeBase<T>, | ||
value: any, | ||
$visited: OpaqueVisitedState, | ||
): Result<T> { | ||
const result = innerSerializeToPlaceholder(targetType, value, $visited); | ||
if (result.cycle) { | ||
return result.unwrap(); | ||
} | ||
return result; | ||
} | ||
function innerSerializeToPlaceholder( | ||
targetType: RuntypeBase, | ||
value: any, | ||
$visited: OpaqueVisitedState, | ||
): ResultWithCycle<any> { | ||
const visited = unwrapVisitedState($visited); | ||
const validator = targetType[internal]; | ||
const cached = visited.get(targetType)?.get(value); | ||
if (cached !== undefined) { | ||
return cached; | ||
} | ||
let result = (validator.serialize || validator.validate)( | ||
value, | ||
(t, v) => innerSerialize(t, v, $visited), | ||
(t, v) => innerSerializeToPlaceholder(t, v, $visited), | ||
); | ||
if (result.cycle) { | ||
visited.set(targetType, (visited.get(targetType) || new Map()).set(value, result)); | ||
return result; | ||
} | ||
return result; | ||
} | ||
export function innerGuard( | ||
targetType: RuntypeBase, | ||
value: any, | ||
$visited: OpaqueGuardVisitedState, | ||
): Failure | undefined { | ||
const visited = unwrapGuardVisitedState($visited); | ||
const validator = targetType[internal]; | ||
if (value && (typeof value === 'object' || typeof value === 'function')) { | ||
const cached = visited.get(targetType)?.has(value); | ||
if (cached) return undefined; | ||
visited.set(targetType, (visited.get(targetType) || new Set()).add(value)); | ||
} | ||
if (validator.test) { | ||
return validator.test(value, (t, v) => innerGuard(t, v, $visited)); | ||
} | ||
let result = validator.validate( | ||
value, | ||
(t, v) => innerGuard(t, v, $visited) || { success: true, value: v as any }, | ||
(t, v) => innerGuard(t, v, $visited) || { success: true, value: v as any }, | ||
); | ||
if (result.cycle) result = result.unwrap(); | ||
if (result.success) return undefined; | ||
else return result; | ||
} |
@@ -13,4 +13,4 @@ import { | ||
Array, | ||
Dictionary, | ||
Record, | ||
Object, | ||
Partial, | ||
@@ -23,9 +23,9 @@ Tuple, | ||
InstanceOf, | ||
Reflect, | ||
} from '.'; | ||
import show from './show'; | ||
import { RuntypeBase } from './runtype'; | ||
class TestClass {} | ||
const cases: [Reflect, string][] = [ | ||
const cases: [RuntypeBase, string][] = [ | ||
[Unknown, 'unknown'], | ||
@@ -45,24 +45,24 @@ [Never, 'never'], | ||
[Array(String).asReadonly(), 'readonly string[]'], | ||
[Dictionary(Array(Boolean)), '{ [_: string]: boolean[] }'], | ||
[Dictionary(Array(Boolean), 'string'), '{ [_: string]: boolean[] }'], | ||
[Dictionary(Array(Boolean), 'number'), '{ [_: number]: boolean[] }'], | ||
[Record({}), '{}'], | ||
[Record({}).asReadonly(), '{}'], | ||
[Record(String, Array(Boolean)), '{ [_: string]: boolean[] }'], | ||
[Record(String, Array(Boolean)), '{ [_: string]: boolean[] }'], | ||
[Record(Number, Array(Boolean)), '{ [_: number]: boolean[] }'], | ||
[Object({}), '{}'], | ||
[Object({}).asReadonly(), '{}'], | ||
[Partial({}), '{}'], | ||
[InstanceOf(TestClass), 'InstanceOf<TestClass>'], | ||
[Array(InstanceOf(TestClass)), 'InstanceOf<TestClass>[]'], | ||
[Record({ x: String, y: Array(Boolean) }), '{ x: string; y: boolean[]; }'], | ||
[Record({ x: String, y: Array(Boolean) }), '{ x: string; y: boolean[]; }'], | ||
[Record({ x: Number }).And(Partial({ y: Number })), '{ x: number; } & { y?: number; }'], | ||
[Object({ x: String, y: Array(Boolean) }), '{ x: string; y: boolean[]; }'], | ||
[Object({ x: String, y: Array(Boolean) }), '{ x: string; y: boolean[]; }'], | ||
[Object({ x: Number }).And(Partial({ y: Number })), '{ x: number; } & { y?: number; }'], | ||
[ | ||
Record({ x: String, y: Array(Boolean) }).asReadonly(), | ||
Object({ x: String, y: Array(Boolean) }).asReadonly(), | ||
'{ readonly x: string; readonly y: boolean[]; }', | ||
], | ||
[Record({ x: String, y: Array(Boolean).asReadonly() }), '{ x: string; y: readonly boolean[]; }'], | ||
[Object({ x: String, y: Array(Boolean).asReadonly() }), '{ x: string; y: readonly boolean[]; }'], | ||
[ | ||
Record({ x: String, y: Array(Boolean).asReadonly() }).asReadonly(), | ||
Object({ x: String, y: Array(Boolean).asReadonly() }).asReadonly(), | ||
'{ readonly x: string; readonly y: readonly boolean[]; }', | ||
], | ||
[Partial({ x: String, y: Array(Boolean) }), '{ x?: string; y?: boolean[]; }'], | ||
[Record({ x: String, y: Array(Boolean) }).asPartial(), '{ x?: string; y?: boolean[]; }'], | ||
[Object({ x: String, y: Array(Boolean) }).asPartial(), '{ x?: string; y?: boolean[]; }'], | ||
[Tuple(Boolean, Number), '[boolean, number]'], | ||
@@ -80,3 +80,3 @@ [Union(Boolean, Number), 'boolean | number'], | ||
[Boolean.Or(Number.And(String)), 'boolean | (number & string)'], | ||
[Boolean.Or(Record({ x: String, y: Number })), 'boolean | { x: string; y: number; }'], | ||
[Boolean.Or(Object({ x: String, y: Number })), 'boolean | { x: string; y: number; }'], | ||
]; | ||
@@ -83,0 +83,0 @@ |
@@ -1,76 +0,34 @@ | ||
import { Reflect } from './index'; | ||
import { RuntypeBase } from './runtype'; | ||
import { isLazyRuntype } from './types/lazy'; | ||
const show = (needsParens: boolean, circular: Set<Reflect>) => (refl: Reflect): string => { | ||
const show = (needsParens: boolean, circular: Set<RuntypeBase<unknown>>) => ( | ||
runtype: RuntypeBase<unknown>, | ||
): string => { | ||
const parenthesize = (s: string) => (needsParens ? `(${s})` : s); | ||
const showChild = (runtype: RuntypeBase<unknown>, needsParens: boolean) => | ||
show(needsParens, circular)(runtype); | ||
if (circular.has(refl)) { | ||
return parenthesize(`CIRCULAR ${refl.tag}`); | ||
if (circular.has(runtype)) { | ||
if (isLazyRuntype(runtype)) { | ||
const underlying = runtype.underlying(); | ||
if (underlying !== runtype) { | ||
return show(needsParens, circular)(underlying); | ||
} | ||
} | ||
return parenthesize(`CIRCULAR ${runtype.tag}`); | ||
} | ||
circular.add(refl); | ||
if (runtype.show) { | ||
circular.add(runtype); | ||
try { | ||
switch (refl.tag) { | ||
// Primitive types | ||
case 'unknown': | ||
case 'never': | ||
case 'void': | ||
case 'boolean': | ||
case 'number': | ||
case 'string': | ||
case 'symbol': | ||
case 'function': | ||
return refl.tag; | ||
// Complex types | ||
case 'literal': { | ||
const { value } = refl; | ||
return typeof value === 'string' ? `"${value}"` : String(value); | ||
} | ||
case 'array': | ||
return `${readonlyTag(refl)}${show(true, circular)(refl.element)}[]`; | ||
case 'dictionary': | ||
return `{ [_: ${refl.key}]: ${show(false, circular)(refl.value)} }`; | ||
case 'record': { | ||
const keys = Object.keys(refl.fields); | ||
return keys.length | ||
? `{ ${keys | ||
.map( | ||
k => | ||
`${readonlyTag(refl)}${k}${partialTag(refl)}: ${show( | ||
false, | ||
circular, | ||
)(refl.fields[k])};`, | ||
) | ||
.join(' ')} }` | ||
: '{}'; | ||
} | ||
case 'tuple': | ||
return `[${refl.components.map(show(false, circular)).join(', ')}]`; | ||
case 'union': | ||
return parenthesize(`${refl.alternatives.map(show(true, circular)).join(' | ')}`); | ||
case 'intersect': | ||
return parenthesize(`${refl.intersectees.map(show(true, circular)).join(' & ')}`); | ||
case 'constraint': | ||
return refl.name || show(needsParens, circular)(refl.underlying); | ||
case 'instanceof': | ||
const name = (refl.ctor as any).name; | ||
return `InstanceOf<${name}>`; | ||
case 'brand': | ||
return show(needsParens, circular)(refl.entity); | ||
try { | ||
return runtype.show({ parenthesize, showChild, needsParens }); | ||
} finally { | ||
circular.delete(runtype); | ||
} | ||
} finally { | ||
circular.delete(refl); | ||
} | ||
throw Error('impossible'); | ||
return runtype.tag; | ||
}; | ||
export default show(false, new Set<Reflect>()); | ||
function partialTag({ isPartial }: { isPartial: boolean }): string { | ||
return isPartial ? '?' : ''; | ||
} | ||
function readonlyTag({ isReadonly }: { isReadonly: boolean }): string { | ||
return isReadonly ? 'readonly ' : ''; | ||
} | ||
export default show(false, new Set<RuntypeBase>()); |
@@ -1,13 +0,16 @@ | ||
import { Runtype, Static, create, innerValidate } from '../runtype'; | ||
import { Static, create, RuntypeBase, Codec, createValidationPlaceholder } from '../runtype'; | ||
type ArrayStaticType<E extends Runtype, RO extends boolean> = RO extends true | ||
? ReadonlyArray<Static<E>> | ||
: Static<E>[]; | ||
export interface ReadonlyArray<E extends RuntypeBase<unknown> = RuntypeBase<unknown>> | ||
extends Codec<readonly Static<E>[]> { | ||
readonly tag: 'array'; | ||
readonly element: E; | ||
readonly isReadonly: true; | ||
} | ||
interface Arr<E extends Runtype, RO extends boolean> extends Runtype<ArrayStaticType<E, RO>> { | ||
tag: 'array'; | ||
element: E; | ||
isReadonly: RO; | ||
asReadonly(): Arr<E, true>; | ||
export { Arr as Array }; | ||
interface Arr<E extends RuntypeBase<unknown> = RuntypeBase<unknown>> extends Codec<Static<E>[]> { | ||
readonly tag: 'array'; | ||
readonly element: E; | ||
readonly isReadonly: false; | ||
asReadonly(): ReadonlyArray<E>; | ||
} | ||
@@ -18,18 +21,18 @@ | ||
*/ | ||
function InternalArr<E extends Runtype, RO extends boolean>( | ||
element: E, | ||
isReadonly: RO, | ||
): Arr<E, RO> { | ||
return withExtraModifierFuncs( | ||
create( | ||
(xs, visited) => { | ||
if (!Array.isArray(xs)) { | ||
return { | ||
success: false, | ||
message: `Expected array, but was ${xs === null ? xs : typeof xs}`, | ||
}; | ||
} | ||
function InternalArr<TElement extends RuntypeBase<unknown>, IsReadonly extends boolean>( | ||
element: TElement, | ||
isReadonly: IsReadonly, | ||
): IsReadonly extends true ? ReadonlyArray<TElement> : Arr<TElement> { | ||
const result = create<ReadonlyArray<TElement> | Arr<TElement>>( | ||
(xs, innerValidate) => { | ||
if (!Array.isArray(xs)) { | ||
return { | ||
success: false, | ||
message: `Expected array, but was ${xs === null ? xs : typeof xs}`, | ||
}; | ||
} | ||
for (const x of xs) { | ||
let validated = innerValidate(element, x, visited); | ||
return createValidationPlaceholder([...xs], placeholder => { | ||
for (let i = 0; i < xs.length; i++) { | ||
const validated = innerValidate(element, xs[i]); | ||
if (!validated.success) { | ||
@@ -39,28 +42,35 @@ return { | ||
message: validated.message, | ||
key: validated.key ? `[${xs.indexOf(x)}].${validated.key}` : `[${xs.indexOf(x)}]`, | ||
key: validated.key ? `[${i}].${validated.key}` : `[${i}]`, | ||
}; | ||
} else { | ||
placeholder[i] = validated.value; | ||
} | ||
} | ||
return { success: true, value: xs }; | ||
}); | ||
}, | ||
{ | ||
tag: 'array', | ||
isReadonly, | ||
element, | ||
show({ showChild }) { | ||
return `${isReadonly ? 'readonly ' : ''}${showChild(element, true)}[]`; | ||
}, | ||
{ tag: 'array', isReadonly, element }, | ||
), | ||
}, | ||
); | ||
if (!isReadonly) { | ||
(result as any).asReadonly = asReadonly; | ||
} | ||
return result as any; | ||
function asReadonly(): ReadonlyArray<TElement> { | ||
return InternalArr(element, true); | ||
} | ||
} | ||
function Arr<E extends Runtype, RO extends boolean>(element: E): Arr<E, false> { | ||
function Arr<TElement extends RuntypeBase<unknown>>(element: TElement): Arr<TElement> { | ||
return InternalArr(element, false); | ||
} | ||
function withExtraModifierFuncs<E extends Runtype, RO extends boolean>(A: any): Arr<E, RO> { | ||
A.asReadonly = asReadonly; | ||
return A; | ||
function asReadonly(): Arr<E, true> { | ||
return InternalArr(A.element, true); | ||
} | ||
export function ReadonlyArray<TElement extends RuntypeBase<unknown>>( | ||
element: TElement, | ||
): ReadonlyArray<TElement> { | ||
return InternalArr(element, true); | ||
} | ||
export { Arr as Array }; |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { create, Codec } from '../runtype'; | ||
export interface Boolean extends Runtype<boolean> { | ||
tag: 'boolean'; | ||
export interface Boolean extends Codec<boolean> { | ||
readonly tag: 'boolean'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
export const Boolean = create<Boolean>( | ||
export const Boolean: Boolean = create<Boolean>( | ||
value => | ||
@@ -13,0 +13,0 @@ typeof value === 'boolean' |
@@ -1,7 +0,7 @@ | ||
import { Runtype, Static, create } from '../runtype'; | ||
import { RuntypeBase, Static, create, Codec } from '../runtype'; | ||
export const RuntypeName = Symbol('RuntypeName'); | ||
export interface Brand<B extends string, A extends Runtype> | ||
extends Runtype< | ||
export interface Brand<B extends string, A extends RuntypeBase<unknown>> | ||
extends Codec< | ||
Static<A> & { | ||
@@ -11,14 +11,15 @@ [RuntypeName]: B; | ||
> { | ||
tag: 'brand'; | ||
brand: B; | ||
entity: A; | ||
readonly tag: 'brand'; | ||
readonly brand: B; | ||
readonly entity: A; | ||
} | ||
export function Brand<B extends string, A extends Runtype>(brand: B, entity: A) { | ||
export function isBrandRuntype(runtype: RuntypeBase): runtype is Brand<string, RuntypeBase> { | ||
return 'tag' in runtype && (runtype as Brand<string, RuntypeBase>).tag === 'brand'; | ||
} | ||
export function Brand<B extends string, A extends RuntypeBase<unknown>>(brand: B, entity: A) { | ||
return create<Brand<B, A>>( | ||
value => { | ||
const validated = entity.validate(value); | ||
return validated.success | ||
? { success: true, value: validated.value as Static<Brand<B, A>> } | ||
: validated; | ||
(value, _innerValidate, innerValidateToPlaceholder) => { | ||
return innerValidateToPlaceholder(entity, value) as any; | ||
}, | ||
@@ -29,4 +30,7 @@ { | ||
entity, | ||
show({ showChild, needsParens }) { | ||
return showChild(entity, needsParens); | ||
}, | ||
}, | ||
); | ||
} |
@@ -1,27 +0,42 @@ | ||
import { Runtype, Static, create } from '../runtype'; | ||
import { RuntypeBase, Static, create, Codec } from '../runtype'; | ||
import { String } from './string'; | ||
import { Unknown } from './unknown'; | ||
export type ConstraintCheck<A extends Runtype> = (x: Static<A>) => boolean | string; | ||
export type ConstraintCheck<A extends RuntypeBase<unknown>> = (x: Static<A>) => boolean | string; | ||
export interface Constraint<A extends Runtype, T extends Static<A> = Static<A>, K = unknown> | ||
extends Runtype<T> { | ||
tag: 'constraint'; | ||
underlying: A; | ||
export function isConstraintRuntype( | ||
runtype: RuntypeBase, | ||
): runtype is Constraint<RuntypeBase, unknown, unknown> { | ||
return ( | ||
'tag' in runtype && (runtype as Constraint<RuntypeBase, unknown, unknown>).tag === 'constraint' | ||
); | ||
} | ||
export interface Constraint< | ||
TUnderlying extends RuntypeBase<unknown>, | ||
TConstrained extends Static<TUnderlying> = Static<TUnderlying>, | ||
TArgs = unknown | ||
> extends Codec<TConstrained> { | ||
readonly tag: 'constraint'; | ||
readonly underlying: TUnderlying; | ||
// See: https://github.com/Microsoft/TypeScript/issues/19746 for why this isn't just | ||
// `constraint: ConstraintCheck<A>` | ||
constraint(x: Static<A>): boolean | string; | ||
name?: string; | ||
args?: K; | ||
constraint(x: Static<TUnderlying>): boolean | string; | ||
readonly name?: string; | ||
readonly args?: TArgs; | ||
} | ||
export function Constraint<A extends Runtype, T extends Static<A> = Static<A>, K = unknown>( | ||
underlying: A, | ||
constraint: ConstraintCheck<A>, | ||
options?: { name?: string; args?: K }, | ||
): Constraint<A, T, K> { | ||
return create<Constraint<A, T, K>>( | ||
value => { | ||
export function Constraint< | ||
TUnderlying extends RuntypeBase<unknown>, | ||
TConstrained extends Static<TUnderlying> = Static<TUnderlying>, | ||
TArgs = unknown | ||
>( | ||
underlying: TUnderlying, | ||
constraint: ConstraintCheck<TUnderlying>, | ||
options?: { name?: string; args?: TArgs }, | ||
): Constraint<TUnderlying, TConstrained, TArgs> { | ||
return create<Constraint<TUnderlying, TConstrained, TArgs>>( | ||
(value, innerValidate) => { | ||
const name = options && options.name; | ||
const validated = underlying.validate(value); | ||
const validated = innerValidate(underlying, value); | ||
@@ -32,6 +47,6 @@ if (!validated.success) { | ||
const result = constraint(validated.value); | ||
if (String.guard(result)) return { success: false, message: result }; | ||
const result = constraint(validated.value as any); | ||
if (String.test(result)) return { success: false, message: result }; | ||
else if (!result) return { success: false, message: `Failed ${name || 'constraint'} check` }; | ||
return { success: true, value: validated.value as T }; | ||
return { success: true, value: validated.value as TConstrained }; | ||
}, | ||
@@ -44,2 +59,6 @@ { | ||
args: options && options.args, | ||
show({ needsParens, showChild }) { | ||
return (options && options.name) || showChild(underlying, needsParens); | ||
}, | ||
}, | ||
@@ -49,5 +68,7 @@ ); | ||
export interface Guard<TConstrained, TArgs = unknown> | ||
extends Constraint<Unknown, TConstrained, TArgs> {} | ||
export const Guard = <T, K = unknown>( | ||
guard: (x: unknown) => x is T, | ||
test: (x: unknown) => x is T, | ||
options?: { name?: string; args?: K }, | ||
) => Unknown.withGuard(guard, options); | ||
): Guard<T, K> => Unknown.withGuard(test, options); |
@@ -1,69 +0,21 @@ | ||
import { Runtype, create, Static, innerValidate } from '../runtype'; | ||
import show from '../show'; | ||
import { String, Number, Record } from '..'; | ||
import { RuntypeBase } from '../runtype'; | ||
export interface StringDictionary<V extends Runtype> extends Runtype<{ [_: string]: Static<V> }> { | ||
tag: 'dictionary'; | ||
key: 'string'; | ||
value: V; | ||
} | ||
export interface StringDictionary<V extends RuntypeBase> extends Record<String, V> {} | ||
export interface NumberDictionary<V extends Runtype> extends Runtype<{ [_: number]: Static<V> }> { | ||
tag: 'dictionary'; | ||
key: 'number'; | ||
value: V; | ||
} | ||
export interface NumberDictionary<V extends RuntypeBase> extends Record<Number, V> {} | ||
/** | ||
* Construct a runtype for arbitrary dictionaries. | ||
* @deprecated use Record(String, value) | ||
*/ | ||
export function Dictionary<V extends Runtype>(value: V, key?: 'string'): StringDictionary<V>; | ||
export function Dictionary<V extends Runtype>(value: V, key?: 'number'): NumberDictionary<V>; | ||
export function Dictionary<V extends Runtype>(value: V, key = 'string'): any { | ||
return create<Runtype>( | ||
(x, visited) => { | ||
if (x === null || x === undefined) { | ||
const a = create<any>(x as never, { tag: 'dictionary', key, value }); | ||
return { success: false, message: `Expected ${show(a)}, but was ${x}` }; | ||
} | ||
if (typeof x !== 'object') { | ||
const a = create<any>(x as never, { tag: 'dictionary', key, value }); | ||
return { success: false, message: `Expected ${show(a.reflect)}, but was ${typeof x}` }; | ||
} | ||
if (Object.getPrototypeOf(x) !== Object.prototype) { | ||
if (!Array.isArray(x)) { | ||
const a = create<any>(x as never, { tag: 'dictionary', key, value }); | ||
return { | ||
success: false, | ||
message: `Expected ${show(a.reflect)}, but was ${Object.getPrototypeOf(x)}`, | ||
}; | ||
} else if (key === 'string') | ||
return { success: false, message: 'Expected dictionary, but was array' }; | ||
} | ||
for (const k in x) { | ||
// Object keys are unknown strings | ||
if (key === 'number') { | ||
if (isNaN(+k)) | ||
return { | ||
success: false, | ||
message: 'Expected dictionary key to be a number, but was string', | ||
}; | ||
} | ||
let validated = innerValidate(value, (x as any)[k], visited); | ||
if (!validated.success) { | ||
return { | ||
success: false, | ||
message: validated.message, | ||
key: validated.key ? `${k}.${validated.key}` : k, | ||
}; | ||
} | ||
} | ||
return { success: true, value: x }; | ||
}, | ||
{ tag: 'dictionary', key, value }, | ||
); | ||
export function Dictionary<V extends RuntypeBase>(value: V, key?: 'string'): StringDictionary<V>; | ||
/** | ||
* @deprecated use Record(Number, value) | ||
*/ | ||
export function Dictionary<V extends RuntypeBase>(value: V, key?: 'number'): NumberDictionary<V>; | ||
export function Dictionary<V extends RuntypeBase>( | ||
value: V, | ||
key: 'number' | 'string' = 'string', | ||
): Record<String | Number, V> { | ||
return Record(key === 'number' ? Number : String, value); | ||
} |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { create, Codec } from '../runtype'; | ||
export interface Function extends Runtype<(...args: any[]) => any> { | ||
tag: 'function'; | ||
export interface Function extends Codec<(...args: any[]) => any> { | ||
readonly tag: 'function'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
export const Function = create<Function>( | ||
export const Function: Function = create<Function>( | ||
value => | ||
@@ -13,0 +13,0 @@ typeof value === 'function' |
@@ -1,2 +0,2 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { create, Codec } from '../runtype'; | ||
@@ -7,8 +7,8 @@ export interface Constructor<V> { | ||
export interface InstanceOf<V> extends Runtype<V> { | ||
tag: 'instanceof'; | ||
ctor: Constructor<V>; | ||
export interface InstanceOf<V = unknown> extends Codec<V> { | ||
readonly tag: 'instanceof'; | ||
readonly ctor: Constructor<V>; | ||
} | ||
export function InstanceOf<V>(ctor: Constructor<V>) { | ||
export function InstanceOf<V>(ctor: Constructor<V>): InstanceOf<V> { | ||
return create<InstanceOf<V>>( | ||
@@ -24,4 +24,11 @@ value => | ||
}, | ||
{ tag: 'instanceof', ctor: ctor }, | ||
{ | ||
tag: 'instanceof', | ||
ctor: ctor, | ||
show() { | ||
const name = (ctor as any).name; | ||
return `InstanceOf<${name}>`; | ||
}, | ||
}, | ||
); | ||
} |
@@ -1,236 +0,84 @@ | ||
import { Runtype, Static, create, innerValidate } from '../runtype'; | ||
import { Static, create, RuntypeBase, Codec, createValidationPlaceholder } from '../runtype'; | ||
import show from '../show'; | ||
export interface Intersect1<A extends Runtype> extends Runtype<Static<A>> { | ||
tag: 'intersect'; | ||
intersectees: [A]; | ||
} | ||
// We use the fact that a union of functions is effectively an intersection of parameters | ||
// e.g. to safely call (({x: 1}) => void | ({y: 2}) => void) you must pass {x: 1, y: 2} | ||
export type StaticIntersect<TIntersectees extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TIntersectees]: TIntersectees[key] extends RuntypeBase | ||
? (parameter: Static<TIntersectees[key]>) => any | ||
: unknown; | ||
}[number] extends (k: infer I) => void | ||
? I | ||
: never; | ||
export interface Intersect2<A extends Runtype, B extends Runtype> | ||
extends Runtype<Static<A> & Static<B>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B]; | ||
export interface Intersect< | ||
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | ||
> extends Codec<StaticIntersect<TIntersectees>> { | ||
readonly tag: 'intersect'; | ||
readonly intersectees: TIntersectees; | ||
} | ||
export interface Intersect3<A extends Runtype, B extends Runtype, C extends Runtype> | ||
extends Runtype<Static<A> & Static<B> & Static<C>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C]; | ||
} | ||
export interface Intersect4< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype | ||
> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D]; | ||
} | ||
export interface Intersect5< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype | ||
> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E]; | ||
} | ||
export interface Intersect6< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype | ||
> extends Runtype<Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F>> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F]; | ||
} | ||
export interface Intersect7< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype | ||
> | ||
extends Runtype< | ||
Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G> | ||
> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G]; | ||
} | ||
export interface Intersect8< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype | ||
> | ||
extends Runtype< | ||
Static<A> & Static<B> & Static<C> & Static<D> & Static<E> & Static<F> & Static<G> & Static<H> | ||
> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H]; | ||
} | ||
export interface Intersect9< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype | ||
> | ||
extends Runtype< | ||
Static<A> & | ||
Static<B> & | ||
Static<C> & | ||
Static<D> & | ||
Static<E> & | ||
Static<F> & | ||
Static<G> & | ||
Static<H> & | ||
Static<I> | ||
> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H, I]; | ||
} | ||
export interface Intersect10< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype, | ||
J extends Runtype | ||
> | ||
extends Runtype< | ||
Static<A> & | ||
Static<B> & | ||
Static<C> & | ||
Static<D> & | ||
Static<E> & | ||
Static<F> & | ||
Static<G> & | ||
Static<H> & | ||
Static<I> & | ||
Static<J> | ||
> { | ||
tag: 'intersect'; | ||
intersectees: [A, B, C, D, E, F, G, H, I, J]; | ||
} | ||
/** | ||
* Construct an intersection runtype from runtypes for its alternatives. | ||
*/ | ||
export function Intersect<A extends Runtype>(A: A): Intersect1<A>; | ||
export function Intersect<A extends Runtype, B extends Runtype>(A: A, B: B): Intersect2<A, B>; | ||
export function Intersect<A extends Runtype, B extends Runtype, C extends Runtype>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
): Intersect3<A, B, C>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype | ||
>(A: A, B: B, C: C, D: D): Intersect4<A, B, C, D>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E): Intersect5<A, B, C, D, E>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F): Intersect6<A, B, C, D, E, F>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Intersect7<A, B, C, D, E, F, G>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Intersect8<A, B, C, D, E, F, G, H>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Intersect9<A, B, C, D, E, F, G, H, I>; | ||
export function Intersect< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype, | ||
J extends Runtype | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
): Intersect10<A, B, C, D, E, F, G, H, I, J>; | ||
export function Intersect(...intersectees: Runtype[]): any { | ||
return create( | ||
(value, visited) => { | ||
TIntersectees extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | ||
>(...intersectees: TIntersectees): Intersect<TIntersectees> { | ||
return create<Intersect<TIntersectees>>( | ||
(value, innerValidate) => { | ||
if (Array.isArray(value)) { | ||
return createValidationPlaceholder<any>([...value], placeholder => { | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, placeholder); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
if (!Array.isArray(validated.value)) { | ||
return { | ||
success: false, | ||
message: `The validator ${show( | ||
targetType, | ||
)} attempted to convert the type of this value from an array to something else. That conversion is not valid as the child of an intersect`, | ||
}; | ||
} | ||
placeholder.splice(0, placeholder.length, ...validated.value); | ||
} | ||
}); | ||
} else if (value && typeof value === 'object') { | ||
return createValidationPlaceholder<any>({}, placeholder => { | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, value); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
if (!(validated.value && typeof validated.value === 'object')) { | ||
return { | ||
success: false, | ||
message: `The validator ${show( | ||
targetType, | ||
)} attempted to convert the type of this value from an object to something else. That conversion is not valid as the child of an intersect`, | ||
}; | ||
} | ||
Object.assign(placeholder, validated.value); | ||
} | ||
}); | ||
} | ||
let result = value; | ||
for (const targetType of intersectees) { | ||
let validated = innerValidate(targetType, value, visited); | ||
let validated = innerValidate(targetType, result); | ||
if (!validated.success) { | ||
return validated; | ||
} | ||
result = validated.value; | ||
} | ||
return { success: true, value }; | ||
return { success: true, value: result }; | ||
}, | ||
{ tag: 'intersect', intersectees }, | ||
{ | ||
tag: 'intersect', | ||
intersectees, | ||
show({ parenthesize, showChild }) { | ||
return parenthesize(`${intersectees.map(v => showChild(v, true)).join(' & ')}`); | ||
}, | ||
}, | ||
); | ||
} |
@@ -1,25 +0,42 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { create, RuntypeBase, Codec, Static } from '../runtype'; | ||
export interface Lazy<TUnderlying extends RuntypeBase<unknown>> extends Codec<Static<TUnderlying>> { | ||
readonly tag: 'lazy'; | ||
readonly underlying: () => TUnderlying; | ||
} | ||
export function lazyValue<T>(fn: () => T) { | ||
let value: T; | ||
return () => { | ||
if (!value) { | ||
value = fn(); | ||
} | ||
return value; | ||
}; | ||
} | ||
export function isLazyRuntype(runtype: RuntypeBase): runtype is Lazy<RuntypeBase> { | ||
return 'tag' in runtype && (runtype as Lazy<RuntypeBase<unknown>>).tag === 'lazy'; | ||
} | ||
/** | ||
* Construct a possibly-recursive Runtype. | ||
*/ | ||
export function Lazy<A extends Runtype>(delayed: () => A) { | ||
const data: any = { | ||
get tag() { | ||
return (getWrapped() as any)['tag']; | ||
export function Lazy<TUnderlying extends RuntypeBase<unknown>>( | ||
delayed: () => TUnderlying, | ||
): Lazy<TUnderlying> { | ||
const underlying = lazyValue(delayed); | ||
return create<Lazy<TUnderlying>>( | ||
(value, _innerValidate, innerValidateToPlaceholder) => { | ||
return innerValidateToPlaceholder(underlying(), value) as any; | ||
}, | ||
}; | ||
let cached: A; | ||
function getWrapped() { | ||
if (!cached) { | ||
cached = delayed(); | ||
for (const k in cached) if (k !== 'tag') data[k] = cached[k]; | ||
} | ||
return cached; | ||
} | ||
return create<A>(x => { | ||
return getWrapped().validate(x); | ||
}, data); | ||
{ | ||
tag: 'lazy', | ||
underlying, | ||
show({ showChild, needsParens }) { | ||
return showChild(underlying(), needsParens); | ||
}, | ||
}, | ||
); | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { RuntypeBase, create, Codec } from '../runtype'; | ||
@@ -6,7 +6,8 @@ /** | ||
*/ | ||
export type LiteralBase = undefined | null | boolean | number | string; | ||
export type LiteralValue = undefined | null | boolean | number | string; | ||
export interface Literal<A extends LiteralBase> extends Runtype<A> { | ||
tag: 'literal'; | ||
value: A; | ||
export interface Literal<TLiteralValue extends LiteralValue = LiteralValue> | ||
extends Codec<TLiteralValue> { | ||
readonly tag: 'literal'; | ||
readonly value: TLiteralValue; | ||
} | ||
@@ -21,6 +22,10 @@ | ||
export function isLiteralRuntype(runtype: RuntypeBase): runtype is Literal { | ||
return 'tag' in runtype && (runtype as Literal).tag === 'literal'; | ||
} | ||
/** | ||
* Construct a runtype for a type literal. | ||
*/ | ||
export function Literal<A extends LiteralBase>(valueBase: A): Literal<A> { | ||
export function Literal<A extends LiteralValue>(valueBase: A): Literal<A> { | ||
return create<Literal<A>>( | ||
@@ -34,3 +39,9 @@ value => | ||
}, | ||
{ tag: 'literal', value: valueBase }, | ||
{ | ||
tag: 'literal', | ||
value: valueBase, | ||
show() { | ||
return typeof valueBase === 'string' ? `"${valueBase}"` : String(valueBase); | ||
}, | ||
}, | ||
); | ||
@@ -37,0 +48,0 @@ } |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { Codec, create } from '../runtype'; | ||
export interface Never extends Runtype<never> { | ||
tag: 'never'; | ||
export interface Never extends Codec<never> { | ||
readonly tag: 'never'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
export const Never = create<Never>( | ||
export const Never: Never = create( | ||
value => ({ | ||
@@ -17,2 +17,2 @@ success: false, | ||
{ tag: 'never' }, | ||
); | ||
) as any; |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { Codec, create } from '../runtype'; | ||
export interface Number extends Runtype<number> { | ||
tag: 'number'; | ||
export interface Number extends Codec<number> { | ||
readonly tag: 'number'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
export const Number = create<Number>( | ||
export const Number: Number = create<Number>( | ||
value => | ||
@@ -13,0 +13,0 @@ typeof value === 'number' |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { create, Codec } from '../runtype'; | ||
export interface String extends Runtype<string> { | ||
tag: 'string'; | ||
export interface String extends Codec<string> { | ||
readonly tag: 'string'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
export const String = create<String>( | ||
export const String: String = create<String>( | ||
value => | ||
@@ -13,0 +13,0 @@ typeof value === 'string' |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { Codec, create } from '../runtype'; | ||
interface Sym extends Runtype<symbol> { | ||
tag: 'symbol'; | ||
interface Sym extends Codec<symbol> { | ||
readonly tag: 'symbol'; | ||
} | ||
@@ -10,3 +10,3 @@ | ||
*/ | ||
const Sym = create<Sym>( | ||
const Sym: Sym = create<Sym>( | ||
value => | ||
@@ -13,0 +13,0 @@ typeof value === 'symbol' |
@@ -1,233 +0,29 @@ | ||
import { Runtype, Static, create, innerValidate } from '../runtype'; | ||
import { create, RuntypeBase, Codec, createValidationPlaceholder } from '../runtype'; | ||
import { Array as Arr } from './array'; | ||
import { Unknown } from './unknown'; | ||
export interface Tuple0 extends Runtype { | ||
tag: 'tuple'; | ||
components: []; | ||
} | ||
export type StaticTuple<TElements extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TElements]: TElements[key] extends RuntypeBase<infer E> ? E : unknown; | ||
}; | ||
export interface Tuple1<A extends Runtype> extends Runtype<[Static<A>]> { | ||
tag: 'tuple'; | ||
components: [A]; | ||
export interface Tuple< | ||
TElements extends readonly RuntypeBase<unknown>[] = readonly RuntypeBase<unknown>[] | ||
> extends Codec<StaticTuple<TElements>> { | ||
readonly tag: 'tuple'; | ||
readonly components: TElements; | ||
} | ||
export interface Tuple2<A extends Runtype, B extends Runtype> | ||
extends Runtype<[Static<A>, Static<B>]> { | ||
tag: 'tuple'; | ||
components: [A, B]; | ||
export function isTupleRuntype(runtype: RuntypeBase): runtype is Tuple<readonly RuntypeBase[]> { | ||
return 'tag' in runtype && (runtype as Tuple<readonly RuntypeBase[]>).tag === 'tuple'; | ||
} | ||
export interface Tuple3<A extends Runtype, B extends Runtype, C extends Runtype> | ||
extends Runtype<[Static<A>, Static<B>, Static<C>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C]; | ||
} | ||
export interface Tuple4<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype> | ||
extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D]; | ||
} | ||
export interface Tuple5< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype | ||
> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E]; | ||
} | ||
export interface Tuple6< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype | ||
> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F]; | ||
} | ||
export interface Tuple7< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype | ||
> extends Runtype<[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>]> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G]; | ||
} | ||
export interface Tuple8< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype | ||
> | ||
extends Runtype< | ||
[Static<A>, Static<B>, Static<C>, Static<D>, Static<E>, Static<F>, Static<G>, Static<H>] | ||
> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H]; | ||
} | ||
export interface Tuple9< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype | ||
> | ||
extends Runtype< | ||
[ | ||
Static<A>, | ||
Static<B>, | ||
Static<C>, | ||
Static<D>, | ||
Static<E>, | ||
Static<F>, | ||
Static<G>, | ||
Static<H>, | ||
Static<I>, | ||
] | ||
> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H, I]; | ||
} | ||
export interface Tuple10< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype, | ||
J extends Runtype | ||
> | ||
extends Runtype< | ||
[ | ||
Static<A>, | ||
Static<B>, | ||
Static<C>, | ||
Static<D>, | ||
Static<E>, | ||
Static<F>, | ||
Static<G>, | ||
Static<H>, | ||
Static<I>, | ||
Static<J>, | ||
] | ||
> { | ||
tag: 'tuple'; | ||
components: [A, B, C, D, E, F, G, H, I, J]; | ||
} | ||
/** | ||
* Construct a tuple runtype from runtypes for each of its elements. | ||
*/ | ||
export function Tuple(): Tuple0; | ||
export function Tuple<A extends Runtype>(A: A): Tuple1<A>; | ||
export function Tuple<A extends Runtype, B extends Runtype>(A: A, B: B): Tuple2<A, B>; | ||
export function Tuple<A extends Runtype, B extends Runtype, C extends Runtype>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
): Tuple3<A, B, C>; | ||
export function Tuple<A extends Runtype, B extends Runtype, C extends Runtype, D extends Runtype>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
): Tuple4<A, B, C, D>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E): Tuple5<A, B, C, D, E>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F): Tuple6<A, B, C, D, E, F>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Tuple7<A, B, C, D, E, F, G>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Tuple8<A, B, C, D, E, F, G, H>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Tuple9<A, B, C, D, E, F, G, H, I>; | ||
export function Tuple< | ||
A extends Runtype, | ||
B extends Runtype, | ||
C extends Runtype, | ||
D extends Runtype, | ||
E extends Runtype, | ||
F extends Runtype, | ||
G extends Runtype, | ||
H extends Runtype, | ||
I extends Runtype, | ||
J extends Runtype | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
): Tuple10<A, B, C, D, E, F, G, H, I, J>; | ||
export function Tuple(...components: Runtype[]): any { | ||
return create( | ||
(x, visited) => { | ||
const validated = innerValidate(Arr(Unknown), x, visited); | ||
T extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | readonly [] | ||
>(...components: T): Tuple<T> { | ||
return create<Tuple<T>>( | ||
(x, innerValidate) => { | ||
const validated = innerValidate(Arr(Unknown), x); | ||
@@ -249,18 +45,28 @@ if (!validated.success) { | ||
for (let i = 0; i < components.length; i++) { | ||
let validatedComponent = innerValidate(components[i], validated.value[i], visited); | ||
return createValidationPlaceholder(validated.value as any, placeholder => { | ||
for (let i = 0; i < components.length; i++) { | ||
let validatedComponent = innerValidate(components[i], validated.value[i]); | ||
if (!validatedComponent.success) { | ||
return { | ||
success: false, | ||
message: validatedComponent.message, | ||
key: validatedComponent.key ? `[${i}].${validatedComponent.key}` : `[${i}]`, | ||
}; | ||
if (!validatedComponent.success) { | ||
return { | ||
success: false, | ||
message: validatedComponent.message, | ||
key: validatedComponent.key ? `[${i}].${validatedComponent.key}` : `[${i}]`, | ||
}; | ||
} | ||
placeholder[i] = validatedComponent.value; | ||
} | ||
} | ||
return { success: true, value: x }; | ||
}); | ||
}, | ||
{ tag: 'tuple', components }, | ||
{ | ||
tag: 'tuple', | ||
components, | ||
show({ showChild }) { | ||
return `[${(components as readonly RuntypeBase<unknown>[]) | ||
.map(e => showChild(e, false)) | ||
.join(', ')}]`; | ||
}, | ||
}, | ||
); | ||
} |
@@ -1,2 +0,2 @@ | ||
import { Union, String, Literal, Record, Number, InstanceOf } from '..'; | ||
import { Union, String, Literal, Object, Number, InstanceOf, Tuple } from '..'; | ||
@@ -19,45 +19,323 @@ const ThreeOrString = Union(Literal(3), String); | ||
it('should pick correct alternative with typescript docs example', () => { | ||
const Square = Record({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Record({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const Circle = Record({ kind: Literal('circle'), radius: Number }); | ||
const Square = Object({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Object({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const Circle = Object({ kind: Literal('circle'), radius: Number }); | ||
const Shape = Union(Square, Rectangle, Circle); | ||
expect(Shape.validate({ kind: 'square', size: new Date() })).toMatchObject({ | ||
success: false, | ||
key: 'size', | ||
}); | ||
expect(Shape.safeParse({ kind: 'square', size: new Date() })).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<kind: 'square'>.size", | ||
"message": "Expected number, but was object", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.validate({ kind: 'rectangle', size: new Date() })).toMatchObject({ | ||
success: false, | ||
key: 'width', | ||
}); | ||
expect(Shape.safeParse({ kind: 'rectangle', size: new Date() })).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<kind: 'rectangle'>.width", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.validate({ kind: 'circle', size: new Date() })).toMatchObject({ | ||
success: false, | ||
key: 'radius', | ||
}); | ||
expect(Shape.safeParse({ kind: 'circle', size: new Date() })).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<kind: 'circle'>.radius", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.validate({ kind: 'other', size: new Date() })).not.toHaveProperty('key'); | ||
expect(Shape.safeParse({ kind: 'other', size: new Date() })).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "kind", | ||
"message": "Expected 'square' | 'rectangle' | 'circle', but was 'other'", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse(42)).toMatchInlineSnapshot(` | ||
Object { | ||
"message": "Expected { kind: \\"square\\"; size: number; } | { kind: \\"rectangle\\"; width: number; height: number; } | { kind: \\"circle\\"; radius: number; }, but was number", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse(null)).toMatchInlineSnapshot(` | ||
Object { | ||
"message": "Expected { kind: \\"square\\"; size: number; } | { kind: \\"rectangle\\"; width: number; height: number; } | { kind: \\"circle\\"; radius: number; }, but was null", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse({ kind: { v: 'circle' }, size: new Date() })).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "kind", | ||
"message": "Expected 'square' | 'rectangle' | 'circle', but was object", | ||
"success": false, | ||
} | ||
`); | ||
}); | ||
it('hould not pick alternative if the discriminant is not unique', () => { | ||
const Square = Record({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Record({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const CircularSquare = Record({ kind: Literal('square'), radius: Number }); | ||
it('should not pick alternative if the discriminant is not unique', () => { | ||
const Square = Object({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Object({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const CircularSquare = Object({ kind: Literal('square'), radius: Number }); | ||
const Shape = Union(Square, Rectangle, CircularSquare); | ||
expect(Shape.validate({ kind: 'square', size: new Date() })).not.toHaveProperty('key'); | ||
expect(Shape.safeParse({ kind: 'square', size: new Date() })).not.toHaveProperty('key'); | ||
}); | ||
it('should not pick alternative if not all types are records', () => { | ||
const Square = Record({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Record({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const Square = Object({ kind: Literal('square'), size: Number }); | ||
const Rectangle = Object({ kind: Literal('rectangle'), width: Number, height: Number }); | ||
const Shape = Union(Square, Rectangle, InstanceOf(Date)); | ||
expect(Shape.validate({ kind: 'square', size: new Date() })).not.toHaveProperty('key'); | ||
expect(Shape.safeParse({ kind: 'square', size: new Date() })).not.toHaveProperty('key'); | ||
}); | ||
it('should handle tuples where the first component is a literal tag', () => { | ||
const Square = Tuple(Literal('square'), Object({ size: Number })); | ||
const Rectangle = Tuple(Literal('rectangle'), Object({ width: Number, height: Number })); | ||
const Circle = Tuple(Literal('circle'), Object({ radius: Number })); | ||
const Shape = Union(Square, Rectangle, Circle); | ||
expect(Shape.safeParse(['square', { size: new Date() }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 'square'>.[1].size", | ||
"message": "Expected number, but was object", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse(['rectangle', { size: new Date() }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 'rectangle'>.[1].width", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse(['circle', { size: new Date() }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 'circle'>.[1].radius", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse(['other', { size: new Date() }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "[0]", | ||
"message": "Expected 'square' | 'rectangle' | 'circle', but was 'other'", | ||
"success": false, | ||
} | ||
`); | ||
}); | ||
it('hould not pick alternative if the tuple discriminant is not unique', () => { | ||
const Square = Tuple(Literal('rectangle'), Object({ size: Number })); | ||
const Rectangle = Tuple(Literal('rectangle'), Object({ width: Number, height: Number })); | ||
const Circle = Tuple(Literal('circle'), Object({ radius: Number })); | ||
const Shape = Union(Square, Rectangle, Circle); | ||
expect(Shape.safeParse(['rectangle', { size: new Date() }])).not.toHaveProperty('key'); | ||
}); | ||
it('hould not pick alternative if the tuple has no discriminant', () => { | ||
const Square = Tuple(String, Object({ size: Number })); | ||
const Rectangle = Tuple(String, Object({ width: Number, height: Number })); | ||
const Circle = Tuple(String, Object({ radius: Number })); | ||
const Shape = Union(Square, Rectangle, Circle); | ||
expect(Shape.safeParse(['rectangle', { size: new Date() }])).not.toHaveProperty('key'); | ||
}); | ||
it('should handle numeric tags', () => { | ||
const Version1 = Tuple(Literal(1), Object({ size: Number })); | ||
const Version2 = Tuple(Literal(2), Object({ width: Number, height: Number })); | ||
const Shape = Union(Version1, Version2); | ||
expect(Shape.safeParse([1, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
1, | ||
Object { | ||
"size": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 2>.[1].width", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { width: 10, height: 20 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
2, | ||
Object { | ||
"height": 20, | ||
"width": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([3, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "[0]", | ||
"message": "Expected 1 | 2, but was 3", | ||
"success": false, | ||
} | ||
`); | ||
const extract = Shape.match( | ||
([_, { size }]) => ({ width: size, height: size }), | ||
([_, dimensions]) => dimensions, | ||
); | ||
expect(extract([1, { size: 20 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"height": 20, | ||
"width": 20, | ||
} | ||
`); | ||
expect(extract([2, { width: 20, height: 20 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"height": 20, | ||
"width": 20, | ||
} | ||
`); | ||
expect(() => extract([2, { size: 20 } as any])).toThrowErrorMatchingInlineSnapshot( | ||
`"Expected number, but was undefined in <[0]: 2>.[1].width"`, | ||
); | ||
}); | ||
it('should handle branded tags', () => { | ||
const Version1 = Tuple(Literal(1).withBrand('version'), Object({ size: Number })); | ||
const Version2 = Tuple( | ||
Literal(2).withBrand('version'), | ||
Object({ width: Number, height: Number }), | ||
); | ||
const Shape = Union(Version1, Version2); | ||
expect(Shape.safeParse([1, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
1, | ||
Object { | ||
"size": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 2>.[1].width", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { width: 10, height: 20 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
2, | ||
Object { | ||
"height": 20, | ||
"width": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([3, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "[0]", | ||
"message": "Expected 1 | 2, but was 3", | ||
"success": false, | ||
} | ||
`); | ||
}); | ||
it('should handle constraints', () => { | ||
const Version1 = Tuple(Literal(1).withBrand('version'), Object({ size: Number })); | ||
const Version2 = Tuple( | ||
Literal(2).withBrand('version'), | ||
Object({ width: Number, height: Number }), | ||
).withConstraint(([_, { width, height }]) => | ||
width > 0 && height > 0 ? true : 'Cannot have both width and height be 0', | ||
); | ||
const Shape = Union(Version1, Version2); | ||
expect(Shape.safeParse([1, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
1, | ||
Object { | ||
"size": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 2>.[1].width", | ||
"message": "Expected number, but was undefined", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { width: 10, height: 20 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"success": true, | ||
"value": Array [ | ||
2, | ||
Object { | ||
"height": 20, | ||
"width": 10, | ||
}, | ||
], | ||
} | ||
`); | ||
expect(Shape.safeParse([3, { size: 10 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "[0]", | ||
"message": "Expected 1 | 2, but was 3", | ||
"success": false, | ||
} | ||
`); | ||
expect(Shape.safeParse([2, { width: 0, height: 0 }])).toMatchInlineSnapshot(` | ||
Object { | ||
"key": "<[0]: 2>", | ||
"message": "Cannot have both width and height be 0", | ||
"success": false, | ||
} | ||
`); | ||
}); | ||
}); | ||
}); |
@@ -1,1971 +0,253 @@ | ||
import { Runtype as Rt, Static, create, innerValidate } from '../runtype'; | ||
import { | ||
Codec, | ||
Static, | ||
create, | ||
RuntypeBase, | ||
InnerValidateHelper, | ||
innerValidate, | ||
createVisitedState, | ||
OpaqueVisitedState, | ||
} from '../runtype'; | ||
import show from '../show'; | ||
import { LiteralBase } from './literal'; | ||
import { hasKey } from '../util'; | ||
import { LiteralValue, isLiteralRuntype } from './literal'; | ||
import { lazyValue, isLazyRuntype } from './lazy'; | ||
import { isObjectRuntype } from './Object'; | ||
import { Result } from '../result'; | ||
import { isTupleRuntype } from './tuple'; | ||
import { isBrandRuntype } from './brand'; | ||
import { isConstraintRuntype } from './constraint'; | ||
import { isParsedValueRuntype } from './ParsedValue'; | ||
import { Never } from '..'; | ||
export interface Union1<A extends Rt> extends Rt<Static<A>> { | ||
tag: 'union'; | ||
alternatives: [A]; | ||
match: Match1<A>; | ||
} | ||
export type StaticUnion<TAlternatives extends readonly RuntypeBase<unknown>[]> = { | ||
[key in keyof TAlternatives]: TAlternatives[key] extends RuntypeBase<unknown> | ||
? Static<TAlternatives[key]> | ||
: unknown; | ||
}[number]; | ||
export interface Union2<A extends Rt, B extends Rt> extends Rt<Static<A> | Static<B>> { | ||
tag: 'union'; | ||
alternatives: [A, B]; | ||
match: Match2<A, B>; | ||
export interface Union<TAlternatives extends readonly RuntypeBase<unknown>[]> | ||
extends Codec<StaticUnion<TAlternatives>> { | ||
readonly tag: 'union'; | ||
readonly alternatives: TAlternatives; | ||
match: Match<TAlternatives>; | ||
} | ||
export interface Union3<A extends Rt, B extends Rt, C extends Rt> | ||
extends Rt<Static<A> | Static<B> | Static<C>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C]; | ||
match: Match3<A, B, C>; | ||
function valueToString(value: any) { | ||
return value === null || typeof value === 'number' || typeof value === 'boolean' | ||
? value | ||
: typeof value === 'string' | ||
? `'${value}'` | ||
: typeof value; | ||
} | ||
export interface Union4<A extends Rt, B extends Rt, C extends Rt, D extends Rt> | ||
extends Rt<Static<A> | Static<B> | Static<C> | Static<D>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D]; | ||
match: Match4<A, B, C, D>; | ||
} | ||
function resolveUnderlyingType(runtype: RuntypeBase, mode: 'p' | 's' | 't'): RuntypeBase { | ||
if (isLazyRuntype(runtype)) return resolveUnderlyingType(runtype.underlying(), mode); | ||
if (isBrandRuntype(runtype)) return resolveUnderlyingType(runtype.entity, mode); | ||
if (isConstraintRuntype(runtype)) return resolveUnderlyingType(runtype.underlying, mode); | ||
if (mode === 'p' && isParsedValueRuntype(runtype)) | ||
return resolveUnderlyingType(runtype.underlying, mode); | ||
if (mode === 't' && isParsedValueRuntype(runtype)) { | ||
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : Never; | ||
} | ||
if (mode === 's' && isParsedValueRuntype(runtype)) { | ||
if (!runtype.config.serialize) { | ||
// this node can never match | ||
return Never; | ||
} | ||
return runtype.config.test ? resolveUnderlyingType(runtype.config.test, mode) : runtype; | ||
} | ||
export interface Union5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt> | ||
extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E]; | ||
match: Match5<A, B, C, D, E>; | ||
return runtype; | ||
} | ||
export interface Union6< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt | ||
> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F]; | ||
match: Match6<A, B, C, D, E, F>; | ||
} | ||
export interface Union7< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt | ||
> extends Rt<Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G>> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G]; | ||
match: Match7<A, B, C, D, E, F, G>; | ||
} | ||
export interface Union8< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt | ||
> | ||
extends Rt< | ||
Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H]; | ||
match: Match8<A, B, C, D, E, F, G, H>; | ||
} | ||
export interface Union9< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I]; | ||
match: Match9<A, B, C, D, E, F, G, H, I>; | ||
} | ||
export interface Union10< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J]; | ||
match: Match10<A, B, C, D, E, F, G, H, I, J>; | ||
} | ||
export interface Union11< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K]; | ||
match: Match11<A, B, C, D, E, F, G, H, I, J, K>; | ||
} | ||
export interface Union12< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L]; | ||
match: Match12<A, B, C, D, E, F, G, H, I, J, K, L>; | ||
} | ||
export interface Union13< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M]; | ||
match: Match13<A, B, C, D, E, F, G, H, I, J, K, L, M>; | ||
} | ||
export interface Union14< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N]; | ||
match: Match14<A, B, C, D, E, F, G, H, I, J, K, L, M, N>; | ||
} | ||
export interface Union15< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]; | ||
match: Match15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>; | ||
} | ||
export interface Union16< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P]; | ||
match: Match16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>; | ||
} | ||
export interface Union17< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q]; | ||
match: Match17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>; | ||
} | ||
export interface Union18< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R]; | ||
match: Match18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R>; | ||
} | ||
export interface Union19< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R> | ||
| Static<S> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S]; | ||
match: Match19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S>; | ||
} | ||
export interface Union20< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt, | ||
T extends Rt | ||
> | ||
extends Rt< | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R> | ||
| Static<S> | ||
| Static<T> | ||
> { | ||
tag: 'union'; | ||
alternatives: [A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T]; | ||
match: Match20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T>; | ||
} | ||
/** | ||
* Construct a union runtype from runtypes for its alternatives. | ||
*/ | ||
export function Union<A extends Rt>(A: A): Union1<A>; | ||
export function Union<A extends Rt, B extends Rt>(A: A, B: B): Union2<A, B>; | ||
export function Union<A extends Rt, B extends Rt, C extends Rt>(A: A, B: B, C: C): Union3<A, B, C>; | ||
export function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
): Union4<A, B, C, D>; | ||
export function Union<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
): Union5<A, B, C, D, E>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt | ||
>(A: A, B: B, C: C, D: D, E: E, F: F): Union6<A, B, C, D, E, F>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G): Union7<A, B, C, D, E, F, G>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H): Union8<A, B, C, D, E, F, G, H>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt | ||
>(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I): Union9<A, B, C, D, E, F, G, H, I>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
): Union10<A, B, C, D, E, F, G, H, I, J>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
): Union11<A, B, C, D, E, F, G, H, I, J, K>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
): Union12<A, B, C, D, E, F, G, H, I, J, K, L>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
): Union13<A, B, C, D, E, F, G, H, I, J, K, L, M>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
): Union14<A, B, C, D, E, F, G, H, I, J, K, L, M, N>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
): Union15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
P: P, | ||
): Union16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
P: P, | ||
Q: Q, | ||
): Union17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
P: P, | ||
Q: Q, | ||
R: R, | ||
): Union18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
P: P, | ||
Q: Q, | ||
R: R, | ||
S: S, | ||
): Union19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S>; | ||
export function Union< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt, | ||
T extends Rt | ||
>( | ||
A: A, | ||
B: B, | ||
C: C, | ||
D: D, | ||
E: E, | ||
F: F, | ||
G: G, | ||
H: H, | ||
I: I, | ||
J: J, | ||
K: K, | ||
L: L, | ||
M: M, | ||
N: N, | ||
O: O, | ||
P: P, | ||
Q: Q, | ||
R: R, | ||
S: S, | ||
T: T, | ||
): Union20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T>; | ||
export function Union(...alternatives: Rt[]): any { | ||
const match = (...cases: any[]) => (x: any) => { | ||
for (let i = 0; i < alternatives.length; i++) { | ||
if (alternatives[i].guard(x)) { | ||
return cases[i](x); | ||
TAlternatives extends readonly [RuntypeBase<unknown>, ...RuntypeBase<unknown>[]] | ||
>(...alternatives: TAlternatives): Union<TAlternatives> { | ||
type TResult = StaticUnion<TAlternatives>; | ||
type InnerValidate = (x: any, innerValidate: InnerValidateHelper) => Result<TResult>; | ||
function validateWithKey( | ||
tag: string | 0, | ||
types: Map<LiteralValue, RuntypeBase<TResult>>, | ||
): InnerValidate { | ||
return (value, innerValidate) => { | ||
if (!value || typeof value !== 'object') { | ||
return { | ||
success: false, | ||
message: `Expected ${show(runtype)}, but was ${value === null ? value : typeof value}`, | ||
}; | ||
} | ||
} | ||
}; | ||
const validator = types.get(value[tag]); | ||
if (validator) { | ||
const result = innerValidate(validator, value); | ||
if (!result.success) { | ||
return { | ||
success: false, | ||
message: result.message, | ||
key: `<${tag === 0 ? `[0]` : tag}: ${valueToString(value[tag])}>${ | ||
result.key ? `.${result.key}` : `` | ||
}`, | ||
}; | ||
} | ||
return result; | ||
} else { | ||
return { | ||
success: false, | ||
message: `Expected ${Array.from(types.keys()) | ||
.map(v => (typeof v === 'string' ? `'${v}'` : v)) | ||
.join(' | ')}, but was ${valueToString(value[tag])}`, | ||
key: tag === 0 ? `[0]` : tag, | ||
}; | ||
} | ||
}; | ||
} | ||
return create( | ||
(value, visited) => { | ||
const commonLiteralFields: { [key: string]: LiteralBase[] } = {}; | ||
for (const alternative of alternatives) { | ||
if (alternative.reflect.tag === 'record') { | ||
for (const fieldName in alternative.reflect.fields) { | ||
const field = alternative.reflect.fields[fieldName]; | ||
if (field.tag === 'literal') { | ||
if (commonLiteralFields[fieldName]) { | ||
if (commonLiteralFields[fieldName].every(value => value !== field.value)) { | ||
commonLiteralFields[fieldName].push(field.value); | ||
} | ||
} else { | ||
commonLiteralFields[fieldName] = [field.value]; | ||
// This must be lazy to avoid eagerly evaluating any circular references | ||
const validatorOf = (mode: 'p' | 's' | 't'): InnerValidate => { | ||
const excludingNever = alternatives.filter(t => resolveUnderlyingType(t, mode).tag !== 'never'); | ||
if (excludingNever.length) { | ||
const alts = excludingNever.map(t => resolveUnderlyingType(t, mode)); | ||
const recordAlternatives = alts.filter(isObjectRuntype); | ||
if (recordAlternatives.length === excludingNever.length) { | ||
const commonLiteralFields: { | ||
[key: string]: Map<LiteralValue, RuntypeBase<TResult>>; | ||
} = {}; | ||
for (let i = 0; i < excludingNever.length; i++) { | ||
for (const fieldName in recordAlternatives[i].fields) { | ||
const field = resolveUnderlyingType(recordAlternatives[i].fields[fieldName], mode); | ||
if (isLiteralRuntype(field)) { | ||
if (!commonLiteralFields[fieldName]) { | ||
commonLiteralFields[fieldName] = new Map(); | ||
} | ||
if (!commonLiteralFields[fieldName].has(field.value)) { | ||
commonLiteralFields[fieldName].set( | ||
field.value, | ||
// @ts-expect-error | ||
excludingNever[i], | ||
); | ||
} | ||
} | ||
} | ||
} | ||
for (const tag of ['type', 'kind', 'tag', ...Object.keys(commonLiteralFields)]) { | ||
if ( | ||
tag in commonLiteralFields && | ||
commonLiteralFields[tag].size === excludingNever.length | ||
) { | ||
return validateWithKey(tag, commonLiteralFields[tag]); | ||
} | ||
} | ||
} | ||
for (const fieldName in commonLiteralFields) { | ||
if (commonLiteralFields[fieldName].length === alternatives.length) { | ||
for (const alternative of alternatives) { | ||
if (alternative.reflect.tag === 'record') { | ||
const field = alternative.reflect.fields[fieldName]; | ||
if ( | ||
field.tag === 'literal' && | ||
hasKey(fieldName, value) && | ||
value[fieldName] === field.value | ||
) { | ||
return innerValidate(alternative, value, visited); | ||
} | ||
const tupleAlternatives = alts.filter(isTupleRuntype); | ||
if (tupleAlternatives.length === excludingNever.length) { | ||
const commonLiteralFields = new Map<LiteralValue, RuntypeBase<TResult>>(); | ||
for (let i = 0; i < excludingNever.length; i++) { | ||
const field = resolveUnderlyingType(tupleAlternatives[i].components[0], mode); | ||
if (isLiteralRuntype(field)) { | ||
if (!commonLiteralFields.has(field.value)) { | ||
commonLiteralFields.set( | ||
field.value, | ||
// @ts-expect-error | ||
excludingNever[i], | ||
); | ||
} | ||
} | ||
} | ||
if (commonLiteralFields.size === excludingNever.length) { | ||
return validateWithKey(0, commonLiteralFields); | ||
} | ||
} | ||
} | ||
return (value, innerValidate) => { | ||
let errorsWithKey = 0; | ||
let lastError; | ||
let lastErrorRuntype; | ||
for (const targetType of alternatives) { | ||
if (innerValidate(targetType, value, visited).success) { | ||
return { success: true, value }; | ||
const result = innerValidate(targetType, value); | ||
if (result.success) { | ||
return result as Result<TResult>; | ||
} | ||
if (result.key) { | ||
errorsWithKey++; | ||
lastError = result; | ||
lastErrorRuntype = targetType; | ||
} | ||
} | ||
const a = create<any>(value as never, { tag: 'union', alternatives }); | ||
if (lastError && lastErrorRuntype && errorsWithKey === 1) { | ||
return { | ||
success: false, | ||
message: lastError.message, | ||
key: `<${show(lastErrorRuntype)}>.${lastError.key}`, | ||
}; | ||
} | ||
return { | ||
success: false, | ||
message: `Expected ${show(a)}, but was ${value === null ? value : typeof value}`, | ||
message: `Expected ${show(runtype)}, but was ${value === null ? value : typeof value}`, | ||
}; | ||
}; | ||
}; | ||
const innerValidator = lazyValue(() => ({ | ||
p: validatorOf('p'), | ||
s: validatorOf('s'), | ||
t: validatorOf('t'), | ||
})); | ||
const runtype: Union<TAlternatives> = create<Union<TAlternatives>>( | ||
{ | ||
validate: (value, visited) => { | ||
return innerValidator().p(value, visited); | ||
}, | ||
serialize: (value, visited) => { | ||
return innerValidator().s(value, visited); | ||
}, | ||
test: (value, visited) => { | ||
const result = innerValidator().s( | ||
value, | ||
(t, v) => visited(t, v) || { success: true, value: v as any }, | ||
); | ||
return result.success ? undefined : result; | ||
}, | ||
}, | ||
{ tag: 'union', alternatives, match }, | ||
{ | ||
tag: 'union', | ||
alternatives, | ||
match: match as any, | ||
show({ parenthesize, showChild }) { | ||
return parenthesize(`${alternatives.map(v => showChild(v, true)).join(' | ')}`); | ||
}, | ||
}, | ||
); | ||
} | ||
export interface Match1<A extends Rt> { | ||
<Z>(a: Case<A, Z>): Matcher1<A, Z>; | ||
} | ||
export interface Match2<A extends Rt, B extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>): Matcher2<A, B, Z>; | ||
} | ||
export interface Match3<A extends Rt, B extends Rt, C extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>): Matcher3<A, B, C, Z>; | ||
} | ||
export interface Match4<A extends Rt, B extends Rt, C extends Rt, D extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>): Matcher4<A, B, C, D, Z>; | ||
} | ||
export interface Match5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt> { | ||
<Z>(a: Case<A, Z>, b: Case<B, Z>, c: Case<C, Z>, d: Case<D, Z>, e: Case<E, Z>): Matcher5< | ||
A, | ||
B, | ||
C, | ||
D, | ||
E, | ||
Z | ||
>; | ||
} | ||
export interface Match6< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
): Matcher6<A, B, C, D, E, F, Z>; | ||
} | ||
export interface Match7< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
g: Case<G, Z>, | ||
): Matcher7<A, B, C, D, E, F, G, Z>; | ||
} | ||
export interface Match8< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
g: Case<G, Z>, | ||
h: Case<H, Z>, | ||
): Matcher8<A, B, C, D, E, F, G, H, Z>; | ||
} | ||
export interface Match9< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
g: Case<G, Z>, | ||
h: Case<H, Z>, | ||
i: Case<I, Z>, | ||
): Matcher9<A, B, C, D, E, F, G, H, I, Z>; | ||
} | ||
export interface Match10< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
g: Case<G, Z>, | ||
h: Case<H, Z>, | ||
i: Case<I, Z>, | ||
j: Case<J, Z>, | ||
): Matcher10<A, B, C, D, E, F, G, H, I, J, Z>; | ||
} | ||
export interface Match11< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt | ||
> { | ||
<Z>( | ||
a: Case<A, Z>, | ||
b: Case<B, Z>, | ||
c: Case<C, Z>, | ||
d: Case<D, Z>, | ||
e: Case<E, Z>, | ||
f: Case<F, Z>, | ||
g: Case<G, Z>, | ||
h: Case<H, Z>, | ||
i: Case<I, Z>, | ||
j: Case<J, Z>, | ||
k: Case<K, Z>, | ||
): Matcher11<A, B, C, D, E, F, G, H, I, J, K, Z>; | ||
} | ||
return runtype; | ||
export interface Match12< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
): Matcher12<A, B, C, D, E, F, G, H, I, J, K, L, Z>; | ||
function match(...cases: any[]) { | ||
return (x: any) => { | ||
const visited: OpaqueVisitedState = createVisitedState(); | ||
for (let i = 0; i < alternatives.length; i++) { | ||
const input = innerValidate(alternatives[i], x, visited); | ||
if (input.success) { | ||
return cases[i](input.value); | ||
} | ||
} | ||
// if none of the types matched, we should fail with an assertion error | ||
runtype.assert(x); | ||
}; | ||
} | ||
} | ||
export interface Match13< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt | ||
> { | ||
export interface Match<A extends readonly RuntypeBase<unknown>[]> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
): Matcher13<A, B, C, D, E, F, G, H, I, J, K, L, M, Z>; | ||
...a: { [key in keyof A]: A[key] extends RuntypeBase<unknown> ? Case<A[key], Z> : never } | ||
): Matcher<A, Z>; | ||
} | ||
export interface Match14< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
): Matcher14<A, B, C, D, E, F, G, H, I, J, K, L, M, N, Z>; | ||
} | ||
export type Case<T extends RuntypeBase<unknown>, Result> = (v: Static<T>) => Result; | ||
export interface Match15< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
): Matcher15<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, Z>; | ||
} | ||
export interface Match16< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
P: Case<P, Z>, | ||
): Matcher16<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Z>; | ||
} | ||
export interface Match17< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
P: Case<P, Z>, | ||
Q: Case<Q, Z>, | ||
): Matcher17<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, Z>; | ||
} | ||
export interface Match18< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
P: Case<P, Z>, | ||
Q: Case<Q, Z>, | ||
R: Case<R, Z>, | ||
): Matcher18<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, Z>; | ||
} | ||
export interface Match19< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
P: Case<P, Z>, | ||
Q: Case<Q, Z>, | ||
R: Case<R, Z>, | ||
S: Case<S, Z>, | ||
): Matcher19<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, Z>; | ||
} | ||
export interface Match20< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt, | ||
T extends Rt | ||
> { | ||
<Z>( | ||
A: Case<A, Z>, | ||
B: Case<B, Z>, | ||
C: Case<C, Z>, | ||
D: Case<D, Z>, | ||
E: Case<E, Z>, | ||
F: Case<F, Z>, | ||
G: Case<G, Z>, | ||
H: Case<H, Z>, | ||
I: Case<I, Z>, | ||
J: Case<J, Z>, | ||
K: Case<K, Z>, | ||
L: Case<L, Z>, | ||
M: Case<M, Z>, | ||
N: Case<N, Z>, | ||
O: Case<O, Z>, | ||
P: Case<P, Z>, | ||
Q: Case<Q, Z>, | ||
R: Case<R, Z>, | ||
S: Case<S, Z>, | ||
T: Case<T, Z>, | ||
): Matcher20<A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, Z>; | ||
} | ||
export type Case<T extends Rt, Result> = (v: Static<T>) => Result; | ||
export type Matcher1<A extends Rt, Z> = (x: Static<A>) => Z; | ||
export type Matcher2<A extends Rt, B extends Rt, Z> = (x: Static<A> | Static<B>) => Z; | ||
export type Matcher3<A extends Rt, B extends Rt, C extends Rt, Z> = ( | ||
x: Static<A> | Static<B> | Static<C>, | ||
export type Matcher<A extends readonly RuntypeBase<unknown>[], Z> = ( | ||
x: { | ||
[key in keyof A]: A[key] extends RuntypeBase<infer Type> ? Type : unknown; | ||
}[number], | ||
) => Z; | ||
export type Matcher4<A extends Rt, B extends Rt, C extends Rt, D extends Rt, Z> = ( | ||
x: Static<A> | Static<B> | Static<C> | Static<D>, | ||
) => Z; | ||
export type Matcher5<A extends Rt, B extends Rt, C extends Rt, D extends Rt, E extends Rt, Z> = ( | ||
x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E>, | ||
) => Z; | ||
export type Matcher6< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
Z | ||
> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F>) => Z; | ||
export type Matcher7< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
Z | ||
> = (x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G>) => Z; | ||
export type Matcher8< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
Z | ||
> = ( | ||
x: Static<A> | Static<B> | Static<C> | Static<D> | Static<E> | Static<F> | Static<G> | Static<H>, | ||
) => Z; | ||
export type Matcher9< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I>, | ||
) => Z; | ||
export type Matcher10< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J>, | ||
) => Z; | ||
export type Matcher11< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K>, | ||
) => Z; | ||
export type Matcher12< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L>, | ||
) => Z; | ||
export type Matcher13< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M>, | ||
) => Z; | ||
export type Matcher14< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N>, | ||
) => Z; | ||
export type Matcher15< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O>, | ||
) => Z; | ||
export type Matcher16< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P>, | ||
) => Z; | ||
export type Matcher17< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q>, | ||
) => Z; | ||
export type Matcher18< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R>, | ||
) => Z; | ||
export type Matcher19< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R> | ||
| Static<S>, | ||
) => Z; | ||
export type Matcher20< | ||
A extends Rt, | ||
B extends Rt, | ||
C extends Rt, | ||
D extends Rt, | ||
E extends Rt, | ||
F extends Rt, | ||
G extends Rt, | ||
H extends Rt, | ||
I extends Rt, | ||
J extends Rt, | ||
K extends Rt, | ||
L extends Rt, | ||
M extends Rt, | ||
N extends Rt, | ||
O extends Rt, | ||
P extends Rt, | ||
Q extends Rt, | ||
R extends Rt, | ||
S extends Rt, | ||
T extends Rt, | ||
Z | ||
> = ( | ||
x: | ||
| Static<A> | ||
| Static<B> | ||
| Static<C> | ||
| Static<D> | ||
| Static<E> | ||
| Static<F> | ||
| Static<G> | ||
| Static<H> | ||
| Static<I> | ||
| Static<J> | ||
| Static<K> | ||
| Static<L> | ||
| Static<M> | ||
| Static<N> | ||
| Static<O> | ||
| Static<P> | ||
| Static<Q> | ||
| Static<R> | ||
| Static<S> | ||
| Static<T>, | ||
) => Z; |
@@ -1,5 +0,5 @@ | ||
import { Runtype, create } from '../runtype'; | ||
import { Codec, create } from '../runtype'; | ||
export interface Unknown extends Runtype { | ||
tag: 'unknown'; | ||
export interface Unknown extends Codec<unknown> { | ||
readonly tag: 'unknown'; | ||
} | ||
@@ -10,2 +10,4 @@ | ||
*/ | ||
export const Unknown = create<Unknown>(value => ({ success: true, value }), { tag: 'unknown' }); | ||
export const Unknown: Unknown = create<Unknown>(value => ({ success: true, value }), { | ||
tag: 'unknown', | ||
}); |
@@ -1,2 +0,2 @@ | ||
// Type guard to determine if an object has a given key | ||
// Type test to determine if an object has a given key | ||
// If this feature gets implemented, we can use `in` instead: https://github.com/Microsoft/TypeScript/issues/10485 | ||
@@ -3,0 +3,0 @@ export function hasKey<K extends string>(k: K, o: {}): o is { [_ in K]: {} } { |
{ | ||
"compilerOptions": { | ||
"module": "commonjs", | ||
"target": "es5", | ||
"lib": ["es2015", "dom"], | ||
"isolatedModules": true, | ||
"module": "ES2015", | ||
"moduleResolution": "node", | ||
"target": "ES2019", | ||
"lib": ["es2019", "dom"], | ||
"strict": true, | ||
@@ -7,0 +9,0 @@ "noUnusedLocals": true, |
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
257155
6843
366
2
10
90