@sinclair/typebox
Advanced tools
Comparing version 0.15.0 to 0.16.0
{ | ||
"name": "@sinclair/typebox", | ||
"version": "0.15.0", | ||
"version": "0.16.0", | ||
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", | ||
@@ -22,3 +22,3 @@ "keywords": [ | ||
"build": "smoke-task build", | ||
"example": "smoke-task example", | ||
"start": "smoke-task example", | ||
"test": "smoke-task spec" | ||
@@ -25,0 +25,0 @@ }, |
113
readme.md
@@ -179,5 +179,4 @@ <div align='center'> | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Literal('foo') │ type T = 'foo' │ const T = { │ | ||
│ │ │ type: 'string', │ | ||
│ │ │ enum: ['foo'] │ | ||
│ const T = Type.Literal(42) │ type T = 42 │ const T = { │ | ||
│ │ │ const: 42 │ | ||
│ │ │ } │ | ||
@@ -203,4 +202,4 @@ │ │ │ │ | ||
│ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ a: Type.Number(), │ a: number, │ type: 'object', │ | ||
│ b: Type.String() │ b: string, │ additionalProperties: false, │ | ||
│ x: Type.Number(), │ x: number, │ type: 'object', │ | ||
│ y: Type.Number() │ y: number │ additionalProperties: false, │ | ||
│ }) │ } │ properties: { │ | ||
@@ -211,3 +210,3 @@ │ │ │ a: { │ | ||
│ │ │ b: { │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
@@ -219,7 +218,7 @@ │ │ │ }, │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Tuple([ │ type T = [string, number] │ const T = { │ | ||
│ Type.String(), │ │ type: 'array', │ | ||
│ const T = Type.Tuple([ │ type T = [number, number] │ const T = { │ | ||
│ Type.Number(), │ │ type: 'array', │ | ||
│ Type.Number() │ │ items: [ │ | ||
│ ]) │ │ { │ | ||
│ │ │ type: 'string' │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ }, { │ | ||
@@ -252,14 +251,22 @@ │ │ │ type: 'number' │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.KeyOf( │ type T = keyof { │ const T = { │ | ||
│ Type.Object({ │ x: number, │ enum: ['x', 'y'] │ | ||
│ x: Type.Number(), │ y: number │ } │ | ||
│ y: Type.Number() │ } │ │ | ||
│ }) │ │ │ | ||
│ ) │ │ │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ const T = Type.Intersect([ │ type T = { │ const T = { │ | ||
│ Type.Object({ │ a: string │ type: 'object', │ | ||
│ a: Type.String() │ } & { │ additionalProperties: false, │ | ||
│ }), │ b: number │ properties: { │ | ||
│ Type.Object({ │ } │ a: { │ | ||
│ b: Type.Number() │ │ type: 'string' │ | ||
│ Type.Object({ │ x: number │ type: 'object', │ | ||
│ x: Type.Number() │ } & { │ additionalProperties: false, │ | ||
│ }), │ y: number │ properties: { │ | ||
│ Type.Object({ │ } │ x: { │ | ||
│ y: Type.Number() │ │ type: 'number' │ | ||
│ }) │ │ }, │ | ||
│ }) │ │ b: { │ | ||
│ }) │ │ y: { │ | ||
│ │ │ type: 'number' │ | ||
│ │ │ } │ | ||
│ │ │ }, │ | ||
│ │ │ required: ['a', 'b'] │ | ||
│ │ │ required: ['x', 'y'] │ | ||
│ │ │ } │ | ||
@@ -297,10 +304,9 @@ │ │ │ │ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Optional( │ y: number │ properties: { │ | ||
│ Type.Number() | }, 'x'> │ x: { │ | ||
│ ), │ │ type: 'number' │ | ||
│ y: Type.Optional( │ │ } │ | ||
│ Type.Number() │ │ }, │ | ||
│ ) │ │ required: ['x'] │ | ||
│ }) │ │ } │ | ||
│ , ['x']) │ │ │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ x: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ ) │ │ } │ | ||
│ │ │ }, │ | ||
│ │ │ required: ['x'] │ | ||
│ │ │ } │ | ||
│ │ │ │ | ||
@@ -310,10 +316,9 @@ ├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
│ Type.Object({ │ x: number, │ type: 'object', │ | ||
│ x: Type.Optional( │ y: number, │ properties: { │ | ||
│ Type.Number() | }, 'y'> │ x: { │ | ||
│ ), │ │ type: 'number' │ | ||
│ y: Type.Optional( │ │ } │ | ||
│ Type.Number() │ │ }, │ | ||
│ ) │ │ required: ['x'] │ | ||
│ }) │ │ } │ | ||
│ , ['y']) │ │ │ | ||
│ x: Type.Number(), │ y: number │ properties: { │ | ||
│ y: Type.Number(), | }, 'x'> │ y: { │ | ||
│ }), ['x'] │ │ type: 'number' │ | ||
│ ) │ │ } │ | ||
│ │ │ }, │ | ||
│ │ │ required: ['y'] │ | ||
│ │ │ } │ | ||
│ │ │ │ | ||
@@ -331,2 +336,3 @@ └────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘ | ||
│ TypeBox │ TypeScript │ JSON Schema │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
@@ -421,2 +427,3 @@ │ const T = Type.Object({ │ type T = { │ const T = { │ | ||
│ TypeBox │ TypeScript │ Extended Schema │ | ||
│ │ │ │ | ||
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤ | ||
@@ -473,3 +480,3 @@ │ const T = Type.Constructor([ │ type T = new ( │ const T = { │ | ||
It is possible to create interfaces from TypeBox types. Consider the following code that creates a `ControllerInterface` type that has a single function `createRecord(...)`. The following is how one would approach this in TypeScript. | ||
It is possible to create interfaces from TypeBox types. Consider the following code that creates a `ControllerInterface` type that has a single function `createRecord(...)`. The following is how one might approach this in TypeScript. | ||
@@ -581,23 +588,19 @@ ```typescript | ||
// Setup | ||
function setupAjv(): Ajv { | ||
const ajv = new Ajv() | ||
ajv.addKeyword('kind') | ||
ajv.addKeyword('modifier') | ||
return addFormats(ajv, [ | ||
'date-time', | ||
'time', | ||
'date', | ||
'email', | ||
'hostname', | ||
'ipv4', | ||
'ipv6', | ||
'uri', | ||
'uri-reference', | ||
'uuid', | ||
'uri-template', | ||
'json-pointer', | ||
'relative-json-pointer', | ||
'regex' | ||
]) | ||
} | ||
const ajv = addFormats(new Ajv(), [ | ||
'date-time', | ||
'time', | ||
'date', | ||
'email', | ||
'hostname', | ||
'ipv4', | ||
'ipv6', | ||
'uri', | ||
'uri-reference', | ||
'uuid', | ||
'uri-template', | ||
'json-pointer', | ||
'relative-json-pointer', | ||
'regex' | ||
]).addKeyword('kind') | ||
.addKeyword('modifier') | ||
@@ -611,3 +614,3 @@ // TypeBox | ||
// Validate | ||
const isValid = setupAjv().validate(User, { | ||
const isValid = ajv.validate(User, { | ||
name: 'dave', | ||
@@ -614,0 +617,0 @@ email: 'dave@domain.com' |
@@ -14,2 +14,3 @@ export declare const ReadonlyOptionalModifier: unique symbol; | ||
}; | ||
export declare const KeyOfKind: unique symbol; | ||
export declare const UnionKind: unique symbol; | ||
@@ -62,4 +63,7 @@ export declare const TupleKind: unique symbol; | ||
export declare type TEnumType = Record<string, string | number>; | ||
export declare type TKey = string | number; | ||
export declare type TKey = string | number | symbol; | ||
export declare type TValue = string | number | boolean; | ||
export declare type TProperties = { | ||
[key: string]: TSchema; | ||
}; | ||
export declare type TTuple<T extends TSchema[]> = { | ||
@@ -73,5 +77,2 @@ kind: typeof TupleKind; | ||
} & CustomOptions; | ||
export declare type TProperties = { | ||
[key: string]: TSchema; | ||
}; | ||
export declare type TObject<T extends TProperties> = { | ||
@@ -88,2 +89,6 @@ kind: typeof ObjectKind; | ||
} & CustomOptions; | ||
export declare type TKeyOf<T extends TKey[]> = { | ||
kind: typeof KeyOfKind; | ||
enum: [...T]; | ||
}; | ||
export declare type TDict<T extends TSchema> = { | ||
@@ -101,4 +106,3 @@ kind: typeof DictKind; | ||
kind: typeof LiteralKind; | ||
type: 'string' | 'number' | 'boolean'; | ||
enum: [T]; | ||
const: T; | ||
} & CustomOptions; | ||
@@ -165,3 +169,3 @@ export declare type TEnum<T extends TKey> = { | ||
} & CustomOptions; | ||
export declare type TSchema = TUnion<any> | TTuple<any> | TObject<any> | TDict<any> | TArray<any> | TEnum<any> | TLiteral<any> | TString | TNumber | TInteger | TBoolean | TNull | TUnknown | TAny | TConstructor<any[], any> | TFunction<any[], any> | TPromise<any> | TUndefined | TVoid; | ||
export declare type TSchema = TUnion<any> | TTuple<any> | TObject<any> | TKeyOf<any> | TDict<any> | TArray<any> | TEnum<any> | TLiteral<any> | TString | TNumber | TInteger | TBoolean | TNull | TUnknown | TAny | TConstructor<any[], any> | TFunction<any[], any> | TPromise<any> | TUndefined | TVoid; | ||
export declare type TRequired<T extends TProperties> = { | ||
@@ -175,2 +179,3 @@ [K in keyof T]: T[K] extends TReadonlyOptional<infer U> ? TReadonly<U> : T[K] extends TReadonly<infer U> ? TReadonly<U> : T[K] extends TOptional<infer U> ? U : T[K]; | ||
export declare type IntersectObjectArray<T> = T extends Array<TObject<infer U>> ? UnionToIntersect<U> : TProperties; | ||
export declare type ObjectPropertyKeys<T> = T extends TObject<infer U> ? PropertyKeys<U> : never; | ||
export declare type PropertyKeys<T extends TProperties> = keyof T; | ||
@@ -196,3 +201,3 @@ export declare type ReadonlyOptionalPropertyKeys<T extends TProperties> = { | ||
}; | ||
export declare type StaticIntersect<T extends TProperties> = StaticProperties<T>; | ||
export declare type StaticKeyOf<T extends TKey[]> = T extends Array<infer K> ? K : never; | ||
export declare type StaticUnion<T extends readonly TSchema[]> = { | ||
@@ -218,3 +223,3 @@ [K in keyof T]: Static<T[K]>; | ||
export declare type StaticPromise<T extends TSchema> = Promise<Static<T>>; | ||
export declare type Static<T> = T extends TUnion<infer U> ? StaticUnion<U> : T extends TTuple<infer U> ? StaticTuple<U> : T extends TObject<infer U> ? StaticObject<U> : T extends TDict<infer U> ? StaticDict<U> : T extends TArray<infer U> ? StaticArray<U> : T extends TEnum<infer U> ? StaticEnum<U> : T extends TLiteral<infer U> ? StaticLiteral<U> : T extends TString ? string : T extends TNumber ? number : T extends TInteger ? number : T extends TBoolean ? boolean : T extends TNull ? null : T extends TUnknown ? unknown : T extends TAny ? any : T extends TConstructor<infer U, infer R> ? StaticConstructor<U, R> : T extends TFunction<infer U, infer R> ? StaticFunction<U, R> : T extends TPromise<infer U> ? StaticPromise<U> : T extends TUndefined ? undefined : T extends TVoid ? void : unknown; | ||
export declare type Static<T> = T extends TKeyOf<infer U> ? StaticKeyOf<U> : T extends TUnion<infer U> ? StaticUnion<U> : T extends TTuple<infer U> ? StaticTuple<U> : T extends TObject<infer U> ? StaticObject<U> : T extends TDict<infer U> ? StaticDict<U> : T extends TArray<infer U> ? StaticArray<U> : T extends TEnum<infer U> ? StaticEnum<U> : T extends TLiteral<infer U> ? StaticLiteral<U> : T extends TString ? string : T extends TNumber ? number : T extends TInteger ? number : T extends TBoolean ? boolean : T extends TNull ? null : T extends TUnknown ? unknown : T extends TAny ? any : T extends TConstructor<infer U, infer R> ? StaticConstructor<U, R> : T extends TFunction<infer U, infer R> ? StaticFunction<U, R> : T extends TPromise<infer U> ? StaticPromise<U> : T extends TUndefined ? undefined : T extends TVoid ? void : never; | ||
export declare class TypeBuilder { | ||
@@ -257,2 +262,4 @@ /** `STANDARD` Modifies a schema object property to be `readonly` and `optional`. */ | ||
Union<T extends TSchema[]>(items: [...T], options?: CustomOptions): TUnion<T>; | ||
/** `STANDARD` Creates a `keyof` schema. */ | ||
KeyOf<T extends TObject<TProperties>>(schema: T, options?: CustomOptions): TKeyOf<ObjectPropertyKeys<T>[]>; | ||
/** `STANDARD` Creates an intersection schema of the given object schemas. */ | ||
@@ -259,0 +266,0 @@ Intersect<T extends TObject<TProperties>[]>(items: [...T], options?: CustomOptions): TObject<IntersectObjectArray<T>>; |
@@ -30,3 +30,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Type = exports.TypeBuilder = exports.VoidKind = exports.UndefinedKind = exports.PromiseKind = exports.FunctionKind = exports.ConstructorKind = exports.AnyKind = exports.UnknownKind = exports.NullKind = exports.BooleanKind = exports.IntegerKind = exports.NumberKind = exports.StringKind = exports.LiteralKind = exports.EnumKind = exports.ArrayKind = exports.DictKind = exports.ObjectKind = exports.TupleKind = exports.UnionKind = exports.ReadonlyModifier = exports.OptionalModifier = exports.ReadonlyOptionalModifier = void 0; | ||
exports.Type = exports.TypeBuilder = exports.VoidKind = exports.UndefinedKind = exports.PromiseKind = exports.FunctionKind = exports.ConstructorKind = exports.AnyKind = exports.UnknownKind = exports.NullKind = exports.BooleanKind = exports.IntegerKind = exports.NumberKind = exports.StringKind = exports.LiteralKind = exports.EnumKind = exports.ArrayKind = exports.DictKind = exports.ObjectKind = exports.TupleKind = exports.UnionKind = exports.KeyOfKind = exports.ReadonlyModifier = exports.OptionalModifier = exports.ReadonlyOptionalModifier = void 0; | ||
// ------------------------------------------------------------------------ | ||
@@ -39,4 +39,5 @@ // Modifiers | ||
// ------------------------------------------------------------------------ | ||
// Schema: Core | ||
// Schema Standard | ||
// ------------------------------------------------------------------------ | ||
exports.KeyOfKind = Symbol('KeyOfKind'); | ||
exports.UnionKind = Symbol('UnionKind'); | ||
@@ -57,3 +58,3 @@ exports.TupleKind = Symbol('TupleKind'); | ||
// ------------------------------------------------------------------------ | ||
// Schema: Extended | ||
// Schema Extended | ||
// ------------------------------------------------------------------------ | ||
@@ -66,13 +67,2 @@ exports.ConstructorKind = Symbol('ConstructorKind'); | ||
// ------------------------------------------------------------------------ | ||
// Reflect | ||
// ------------------------------------------------------------------------ | ||
function reflect(value) { | ||
switch (typeof value) { | ||
case 'string': return 'string'; | ||
case 'number': return 'number'; | ||
case 'boolean': return 'boolean'; | ||
default: return 'unknown'; | ||
} | ||
} | ||
// ------------------------------------------------------------------------ | ||
// Clone | ||
@@ -149,7 +139,3 @@ // ------------------------------------------------------------------------ | ||
Literal(value, options = {}) { | ||
const type = reflect(value); | ||
if (type === 'unknown') { | ||
throw Error(`Invalid literal value '${value}'`); | ||
} | ||
return { ...options, kind: exports.LiteralKind, type, enum: [value] }; | ||
return { ...options, kind: exports.LiteralKind, const: value }; | ||
} | ||
@@ -192,2 +178,7 @@ /** `STANDARD` Creates a `string` schema. */ | ||
} | ||
/** `STANDARD` Creates a `keyof` schema. */ | ||
KeyOf(schema, options = {}) { | ||
const keys = Object.keys(schema.properties); | ||
return { ...options, kind: exports.KeyOfKind, enum: keys }; | ||
} | ||
/** `STANDARD` Creates an intersection schema of the given object schemas. */ | ||
@@ -194,0 +185,0 @@ Intersect(items, options = {}) { |
75661
613
552