mirror of
https://github.com/zoriya/typebox.git
synced 2025-12-06 06:46:10 +00:00
Revision 0.32.9 (#731)
* Optimize Composite * Set and Composite Tests * Version
This commit is contained in:
@@ -56,7 +56,7 @@ export interface TBoolean extends Types.TSchema {
|
||||
// --------------------------------------------------------------------------
|
||||
export type InferUnion<T extends TStruct[], D extends string, Index = string> =
|
||||
T extends [infer L extends TStruct, ...infer R extends TStruct[]]
|
||||
? Types.Evaluate<{ [_ in D]: Index } & Types.Static<L>> | InferUnion<R, D, Types.Increment<Types.Assert<Index, string>>>
|
||||
? Types.Evaluate<{ [_ in D]: Index } & Types.Static<L>> | InferUnion<R, D, Types.TIncrement<Types.Assert<Index, string>>>
|
||||
: never
|
||||
|
||||
export interface TUnion<T extends TStruct[] = TStruct[], D extends string = string> extends Types.TSchema {
|
||||
|
||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.32.8",
|
||||
"version": "0.32.9",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.32.8",
|
||||
"version": "0.32.9",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@arethetypeswrong/cli": "^0.13.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@sinclair/typebox",
|
||||
"version": "0.32.8",
|
||||
"version": "0.32.9",
|
||||
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
|
||||
"keywords": [
|
||||
"typescript",
|
||||
|
||||
33
src/index.ts
33
src/index.ts
@@ -34,9 +34,37 @@ export { PatternBoolean, PatternBooleanExact, PatternNumber, PatternNumberExact,
|
||||
export { TypeRegistry, FormatRegistry } from './type/registry/index'
|
||||
export { TypeGuard, ValueGuard } from './type/guard/index'
|
||||
export { CloneType, CloneRest } from './type/clone/type'
|
||||
// ------------------------------------------------------------------
|
||||
// Error
|
||||
// ------------------------------------------------------------------
|
||||
export { TypeBoxError } from './type/error/index'
|
||||
// ------------------------------------------------------------------
|
||||
// Type
|
||||
// Sets
|
||||
// ------------------------------------------------------------------
|
||||
export {
|
||||
SetComplement,
|
||||
SetDistinct,
|
||||
SetIncludes,
|
||||
SetIntersect,
|
||||
SetIntersectMany,
|
||||
SetIsSubset,
|
||||
SetUnion,
|
||||
SetUnionMany,
|
||||
type TSetComplement,
|
||||
type TSetDistinct,
|
||||
type TSetIncludes,
|
||||
type TSetIntersect,
|
||||
type TSetIntersectMany,
|
||||
type TSetIsSubset,
|
||||
type TSetUnion,
|
||||
type TSetUnionMany,
|
||||
} from './type/sets/index'
|
||||
// ------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ------------------------------------------------------------------
|
||||
export { Increment, type TIncrement, type Assert, type AssertType, type AssertRest, type AssertProperties, type Ensure, type Evaluate, type TupleToIntersect, type TupleToUnion, type UnionToTuple } from './type/helpers/index'
|
||||
// ------------------------------------------------------------------
|
||||
// Types
|
||||
// ------------------------------------------------------------------
|
||||
export { Any, type TAny } from './type/any/index'
|
||||
export { Array, type TArray, type ArrayOptions } from './type/array/index'
|
||||
@@ -55,7 +83,6 @@ export { Exclude, type TExclude, type TExcludeFromMappedResult } from './type/ex
|
||||
export { Extends, ExtendsCheck, ExtendsResult, ExtendsUndefinedCheck, type TExtends, type ExtendsFromMappedResult, type ExtendsFromMappedKey } from './type/extends/index'
|
||||
export { Extract, type TExtract, type TExtractFromMappedResult } from './type/extract/index'
|
||||
export { Function, type TFunction } from './type/function/index'
|
||||
export { Increment, type Assert, type AssertType, type AssertRest, type AssertProperties, type Ensure, type Evaluate, type TupleToIntersect, type TupleToUnion, type UnionToTuple } from './type/helpers/index'
|
||||
export {
|
||||
Index,
|
||||
IndexPropertyKeys,
|
||||
@@ -102,7 +129,7 @@ export { type TSchema, type TKind, type SchemaOptions, type TAnySchema } from '.
|
||||
export { type Static, type StaticDecode, type StaticEncode, type TDecodeType, type TDecodeRest, type TDecodeProperties } from './type/static/index'
|
||||
export { Strict } from './type/strict/index'
|
||||
export { String, type TString, type StringOptions, type StringFormatOption, type StringContentEncodingOption } from './type/string/index'
|
||||
export { Symbol, type TSymbol, type TSymbolValue as SymbolValue } from './type/symbol/index'
|
||||
export { Symbol, type TSymbol, type TSymbolValue } from './type/symbol/index'
|
||||
export {
|
||||
TemplateLiteral,
|
||||
TemplateLiteralSyntax,
|
||||
|
||||
@@ -27,44 +27,95 @@ THE SOFTWARE.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import type { TSchema } from '../schema/index'
|
||||
import type { UnionToTuple, Assert, Ensure, Evaluate } from '../helpers/index'
|
||||
import type { Evaluate } from '../helpers/index'
|
||||
import { IntersectEvaluated, type TIntersectEvaluated } from '../intersect/index'
|
||||
import { IndexFromPropertyKeys, type TIndexFromPropertyKeys } from '../indexed/index'
|
||||
import { KeyOfPropertyKeys, type TKeyOfPropertyKeys } from '../keyof/index'
|
||||
import { type TNever } from '../never/index'
|
||||
import { Object, type TObject, type TProperties, type ObjectOptions } from '../object/index'
|
||||
import { Intersect, type TIntersect } from '../intersect/index'
|
||||
import { Index, type TIndex } from '../indexed/index'
|
||||
import { KeyOfPropertyKeys } from '../keyof/index'
|
||||
import { SetDistinct, TSetDistinct } from '../sets/index'
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// TCompositeKeys
|
||||
// TypeGuard
|
||||
// ------------------------------------------------------------------
|
||||
import { IsNever } from '../guard/type'
|
||||
// ------------------------------------------------------------------
|
||||
// CompositeKeys
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TCompositeKeys<T extends TObject[], Acc extends PropertyKey = never> =
|
||||
T extends [infer L extends TObject, ...infer R extends TObject[]]
|
||||
? TCompositeKeys<R, Acc | keyof L['properties']>
|
||||
type TCompositeKeys<T extends TSchema[], Acc extends PropertyKey[] = []> = (
|
||||
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
|
||||
? TCompositeKeys<R, TSetDistinct<[...Acc, ...TKeyOfPropertyKeys<L>]>>
|
||||
: Acc
|
||||
// ------------------------------------------------------------------
|
||||
// TCompositeIndex
|
||||
// ------------------------------------------------------------------
|
||||
)
|
||||
// prettier-ignore
|
||||
type TCompositeIndex<T extends TIntersect<TObject[]>, K extends string[], Acc extends TProperties = {}> =
|
||||
K extends [infer L extends string, ...infer R extends string[]]
|
||||
? TCompositeIndex<T, R, Acc & { [_ in L]: TIndex<T, [L]> }>
|
||||
: Acc
|
||||
// prettier-ignore
|
||||
type TCompositeReduce<T extends TObject[]> = UnionToTuple<TCompositeKeys<T>> extends infer K
|
||||
? Evaluate<TCompositeIndex<TIntersect<T>, Assert<K, string[]>>>
|
||||
: {} // ^ indexed via intersection of T
|
||||
// ------------------------------------------------------------------
|
||||
// TComposite
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
export type TComposite<T extends TObject[]> = TIntersect<T> extends TIntersect
|
||||
? Ensure<TObject<TCompositeReduce<T>>>
|
||||
: Ensure<TObject<{}>>
|
||||
|
||||
/** `[Json]` Creates a Composite object type */
|
||||
export function Composite<T extends TObject[]>(T: [...T], options?: ObjectOptions): TComposite<T> {
|
||||
const intersect: TSchema = Intersect(T, {})
|
||||
const keys = KeyOfPropertyKeys(intersect) as string[]
|
||||
const properties = keys.reduce((acc, key) => ({ ...acc, [key]: Index(intersect, [key]) }), {} as TProperties)
|
||||
return Object(properties, options) as TComposite<T>
|
||||
function CompositeKeys<T extends TSchema[]>(T: [...T]): TCompositeKeys<T> {
|
||||
return T.reduce((Acc, L) => {
|
||||
return SetDistinct([...Acc, ...KeyOfPropertyKeys(L)]) as never
|
||||
}, []) as never
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// FilterNever
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TFilterNever<T extends TSchema[], Acc extends TSchema[] = []> = (
|
||||
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
|
||||
? L extends TNever
|
||||
? Acc
|
||||
: TFilterNever<R, [...Acc, L]>
|
||||
: Acc
|
||||
)
|
||||
// prettier-ignore
|
||||
function FilterNever<T extends TSchema[]>(T: [...T]): TFilterNever<T> {
|
||||
return T.filter(L => !IsNever(L)) as never
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// CompositeProperty
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TCompositeProperty<T extends TSchema[], K extends PropertyKey, Acc extends TSchema[] = []> = (
|
||||
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
|
||||
? TCompositeProperty<R, K, TFilterNever<[...Acc, ...TIndexFromPropertyKeys<L, [K]>]>>
|
||||
: Acc
|
||||
)
|
||||
// prettier-ignore
|
||||
function CompositeProperty<T extends TSchema[], K extends PropertyKey>(T: [...T], K: K): TCompositeProperty<T, K> {
|
||||
return T.reduce((Acc, L) => {
|
||||
return FilterNever([...Acc, ...IndexFromPropertyKeys(L, [K])])
|
||||
}, []) as never
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// CompositeProperties
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TCompositeProperties<T extends TSchema[], K extends PropertyKey[], Acc = {}> = (
|
||||
K extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]]
|
||||
? TCompositeProperties<T, R, Acc & { [_ in L]: TIntersectEvaluated<TCompositeProperty<T, L>> }>
|
||||
: Acc
|
||||
)
|
||||
// prettier-ignore
|
||||
function CompositeProperties<T extends TSchema[], K extends PropertyKey[] = []>(T: [...T], K: [...K]): TCompositeProperties<T, K> {
|
||||
return K.reduce((Acc, L) => {
|
||||
return { ...Acc, [L]: IntersectEvaluated(CompositeProperty(T, L)) }
|
||||
}, {}) as never
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Composite
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type TCompositeEvaluate<
|
||||
T extends TSchema[],
|
||||
K extends PropertyKey[] = TCompositeKeys<T>,
|
||||
P extends TProperties = Evaluate<TCompositeProperties<T, K>>,
|
||||
R extends TObject = TObject<P>
|
||||
> = R
|
||||
// prettier-ignore
|
||||
export type TComposite<T extends TSchema[]> = TCompositeEvaluate<T>
|
||||
|
||||
// prettier-ignore
|
||||
export function Composite<T extends TSchema[]>(T: [...T], options: ObjectOptions = {}): TComposite<T> {
|
||||
const K = CompositeKeys(T)
|
||||
const P = CompositeProperties(T, K)
|
||||
const R = Object(P, options)
|
||||
return R as TComposite<T>
|
||||
}
|
||||
|
||||
@@ -56,10 +56,10 @@ type IncrementStep<T extends string> = T extends IncrementBase['m']
|
||||
: `${IncrementTake<L>}${R}`
|
||||
: never
|
||||
type IncrementReverse<T extends string> = T extends `${infer L}${infer R}` ? `${IncrementReverse<R>}${L}` : T
|
||||
export type Increment<T extends string> = IncrementReverse<IncrementStep<IncrementReverse<T>>>
|
||||
export type TIncrement<T extends string> = IncrementReverse<IncrementStep<IncrementReverse<T>>>
|
||||
/** Increments the given string value + 1 */
|
||||
export function Increment<T extends string>(T: T): Increment<T> {
|
||||
return (parseInt(T) + 1).toString() as Increment<T>
|
||||
export function Increment<T extends string>(T: T): TIncrement<T> {
|
||||
return (parseInt(T) + 1).toString() as TIncrement<T>
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Helper: Type Asserts
|
||||
|
||||
@@ -27,7 +27,7 @@ THE SOFTWARE.
|
||||
---------------------------------------------------------------------------*/
|
||||
|
||||
import type { TSchema } from '../schema/index'
|
||||
import { type ZeroString, type UnionToTuple, Increment } from '../helpers/index'
|
||||
import { type ZeroString, type UnionToTuple, type TIncrement } from '../helpers/index'
|
||||
import type { TRecursive } from '../recursive/index'
|
||||
import type { TIntersect } from '../intersect/index'
|
||||
import type { TUnion } from '../union/index'
|
||||
@@ -59,31 +59,31 @@ function FromRest<T extends TSchema[]>(T: [...T]): TFromRest<T> {
|
||||
// FromIntersect
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type FromIntersect<
|
||||
type TFromIntersect<
|
||||
T extends TSchema[],
|
||||
C extends PropertyKey[][] = TFromRest<T>,
|
||||
R extends PropertyKey[] = TSetUnionMany<C>
|
||||
> = R
|
||||
// prettier-ignore
|
||||
function FromIntersect<T extends TSchema[]>(T: [...T]): FromIntersect<T> {
|
||||
function FromIntersect<T extends TSchema[]>(T: [...T]): TFromIntersect<T> {
|
||||
const C = FromRest(T) as PropertyKey[][]
|
||||
const R = SetUnionMany(C)
|
||||
return R as FromIntersect<T>
|
||||
return R as TFromIntersect<T>
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// FromUnion
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
type FromUnion<
|
||||
type TFromUnion<
|
||||
T extends TSchema[],
|
||||
C extends PropertyKey[][] = TFromRest<T>,
|
||||
R extends PropertyKey[] = TSetIntersectMany<C>
|
||||
> = R
|
||||
// prettier-ignore
|
||||
function FromUnion<T extends TSchema[]>(T: [...T]): FromUnion<T> {
|
||||
function FromUnion<T extends TSchema[]>(T: [...T]): TFromUnion<T> {
|
||||
const C = FromRest(T) as PropertyKey[][]
|
||||
const R = SetIntersectMany(C)
|
||||
return R as FromUnion<T>
|
||||
return R as TFromUnion<T>
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// FromTuple
|
||||
@@ -91,7 +91,7 @@ function FromUnion<T extends TSchema[]>(T: [...T]): FromUnion<T> {
|
||||
// prettier-ignore
|
||||
type TFromTuple<T extends TSchema[], I extends string = ZeroString, Acc extends PropertyKey[] = []> =
|
||||
T extends [infer _ extends TSchema, ...infer R extends TSchema[]]
|
||||
? TFromTuple<R, Increment<I>, [...Acc, I]>
|
||||
? TFromTuple<R, TIncrement<I>, [...Acc, I]>
|
||||
: Acc
|
||||
// prettier-ignore
|
||||
function FromTuple<T extends TSchema[]>(T: [...T]): TFromTuple<T> {
|
||||
@@ -142,8 +142,8 @@ function FromPatternProperties(patternProperties: Record<PropertyKey, TSchema>):
|
||||
// prettier-ignore
|
||||
export type TKeyOfPropertyKeys<T extends TSchema> = (
|
||||
T extends TRecursive<infer S> ? TKeyOfPropertyKeys<S> :
|
||||
T extends TIntersect<infer S> ? FromIntersect<S> :
|
||||
T extends TUnion<infer S> ? FromUnion<S> :
|
||||
T extends TIntersect<infer S> ? TFromIntersect<S> :
|
||||
T extends TUnion<infer S> ? TFromUnion<S> :
|
||||
T extends TTuple<infer S> ? TFromTuple<S> :
|
||||
T extends TArray<infer S> ? TFromArray<S> :
|
||||
T extends TObject<infer S> ? TFromProperties<S> :
|
||||
|
||||
@@ -37,7 +37,7 @@ export type TSetIncludes<T extends PropertyKey[], S extends PropertyKey> = (
|
||||
: TSetIncludes<R, S>
|
||||
: false
|
||||
)
|
||||
/** Returns true if element S is in the set of T */
|
||||
/** Returns true if element right is in the set of left */
|
||||
// prettier-ignore
|
||||
export function SetIncludes<T extends PropertyKey[], S extends PropertyKey>(T: [...T], S: S): TSetIncludes<T, S> {
|
||||
return T.includes(S) as TSetIncludes<T, S>
|
||||
@@ -46,16 +46,16 @@ export function SetIncludes<T extends PropertyKey[], S extends PropertyKey>(T: [
|
||||
// SetIsSubset
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
export type SetIsSubset<T extends PropertyKey[], S extends PropertyKey[]> = (
|
||||
export type TSetIsSubset<T extends PropertyKey[], S extends PropertyKey[]> = (
|
||||
T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]]
|
||||
? TSetIncludes<S, L> extends true
|
||||
? SetIsSubset<R, S>
|
||||
? TSetIsSubset<R, S>
|
||||
: false
|
||||
: true
|
||||
)
|
||||
/** Returns true if T is a subset of S */
|
||||
export function SetIsSubset<T extends PropertyKey[], S extends PropertyKey[]>(T: [...T], S: [...S]): SetIsSubset<T, S> {
|
||||
return T.every((L) => SetIncludes(S, L)) as SetIsSubset<T, S>
|
||||
/** Returns true if left is a subset of right */
|
||||
export function SetIsSubset<T extends PropertyKey[], S extends PropertyKey[]>(T: [...T], S: [...S]): TSetIsSubset<T, S> {
|
||||
return T.every((L) => SetIncludes(S, L)) as TSetIsSubset<T, S>
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// SetDistinct
|
||||
@@ -78,7 +78,7 @@ export function SetDistinct<T extends PropertyKey[]>(T: [...T]): TSetDistinct<T>
|
||||
export type TSetIntersect<T extends PropertyKey[], S extends PropertyKey[], Acc extends PropertyKey[] = []> = (
|
||||
T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]]
|
||||
? TSetIncludes<S, L> extends true
|
||||
? TSetIntersect<R, S, [L, ...Acc]>
|
||||
? TSetIntersect<R, S, [...Acc, L]>
|
||||
: TSetIntersect<R, S, [...Acc]>
|
||||
: Acc
|
||||
)
|
||||
@@ -90,14 +90,12 @@ export function SetIntersect<T extends PropertyKey[], S extends PropertyKey[]>(T
|
||||
// SetUnion
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
export type TSetUnion<T extends PropertyKey[], S extends PropertyKey[], Acc extends PropertyKey[] = S> = (
|
||||
T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]]
|
||||
? TSetUnion<R, S, [...Acc, L]>
|
||||
: Acc
|
||||
export type TSetUnion<T extends PropertyKey[], S extends PropertyKey[]> = (
|
||||
[...T, ...S]
|
||||
)
|
||||
/** Returns the Union of the given sets */
|
||||
export function SetUnion<T extends PropertyKey[], S extends PropertyKey[]>(T: [...T], S: [...S]): TSetUnion<T, S> {
|
||||
return [...T, ...S] as never
|
||||
return [...T, ...S]
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// SetComplement
|
||||
@@ -119,17 +117,35 @@ export function SetComplement<T extends PropertyKey[], S extends PropertyKey[]>(
|
||||
// SetIntersectMany
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
export type TSetIntersectMany<T extends PropertyKey[][], Acc extends PropertyKey[] = []> = (
|
||||
T extends [infer L extends PropertyKey[]] ? L :
|
||||
type TSetIntersectManyResolve<T extends PropertyKey[][], Acc extends PropertyKey[]> = (
|
||||
T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]]
|
||||
? TSetIntersectMany<R, TSetIntersect<Acc, L>>
|
||||
? TSetIntersectManyResolve<R, TSetIntersect<Acc, L>>
|
||||
: Acc
|
||||
)
|
||||
/** Returns the Intersect of multiple sets */
|
||||
// prettier-ignore
|
||||
function SetIntersectManyResolve<T extends PropertyKey[][], Acc extends PropertyKey[]>(T: [...T], Init: Acc): TSetIntersectManyResolve<T, Acc> {
|
||||
return T.reduce((Acc: PropertyKey[], L: PropertyKey[]) => {
|
||||
return SetIntersect(Acc, L)
|
||||
}, Init) as never
|
||||
}
|
||||
// prettier-ignore
|
||||
export type TSetIntersectMany<T extends PropertyKey[][]> = (
|
||||
T extends [infer L extends PropertyKey[]]
|
||||
? L
|
||||
// Use left to initialize the accumulator for resolve
|
||||
: T extends [infer L extends PropertyKey[], ...infer R extends PropertyKey[][]]
|
||||
? TSetIntersectManyResolve<R, L>
|
||||
: []
|
||||
)
|
||||
// prettier-ignore
|
||||
export function SetIntersectMany<T extends PropertyKey[][]>(T: [...T]): TSetIntersectMany<T> {
|
||||
return (
|
||||
T.length === 1 ? T[0] : T.reduce((Acc, L) => [...SetIntersect(Acc, L)], [])
|
||||
T.length === 1
|
||||
? T[0]
|
||||
// Use left to initialize the accumulator for resolve
|
||||
: T.length > 1
|
||||
? SetIntersectManyResolve(T.slice(1), T[0])
|
||||
: []
|
||||
) as TSetIntersectMany<T>
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
|
||||
@@ -130,8 +130,8 @@ export class JsonTypeBuilder {
|
||||
return Capitalize(schema, options)
|
||||
}
|
||||
/** `[Json]` Creates a Composite object type */
|
||||
public Composite<T extends TObject[]>(objects: [...T], options?: ObjectOptions): TComposite<T> {
|
||||
return Composite(objects, options) as any // (error) TS 5.4.0-dev - review TComposite implementation
|
||||
public Composite<T extends TSchema[]>(schemas: [...T], options?: ObjectOptions): TComposite<T> {
|
||||
return Composite(schemas, options) // (error) TS 5.4.0-dev - review TComposite implementation
|
||||
}
|
||||
/** `[JavaScript]` Creates a readonly const type from the given value. */
|
||||
public Const</* const (not supported in 4.0) */ T>(value: T, options: SchemaOptions = {}): TConst<T> {
|
||||
|
||||
@@ -91,4 +91,21 @@ describe('compiler-ajv/Composite', () => {
|
||||
const B = Type.Composite([T])
|
||||
Assert.IsEqual(A, B)
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite intersection', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() })
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ y: Type.Number() })
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ z: Type.Number() })
|
||||
]),
|
||||
])
|
||||
Ok(T, { x: 1, y: 2, z: 3 })
|
||||
Fail(T, { x: 1, y: 2, z: '3' })
|
||||
Fail(T, { x: 1, y: 2 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -81,4 +81,21 @@ describe('compiler/Composite', () => {
|
||||
Fail(T, { x: { x: '1' }, y: { x: '' } })
|
||||
Fail(T, { x: { x: 1 }, y: { x: 1 } })
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite intersection', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() })
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ y: Type.Number() })
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ z: Type.Number() })
|
||||
]),
|
||||
])
|
||||
Ok(T, { x: 1, y: 2, z: 3 })
|
||||
Fail(T, { x: 1, y: 2, z: '3' })
|
||||
Fail(T, { x: 1, y: 2 })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -36,8 +36,8 @@ describe('type/guard/TComposite', () => {
|
||||
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
|
||||
Assert.IsEqual(T.required, undefined)
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should produce required property if some composited properties are not optional', () => {
|
||||
// prettier-ignore
|
||||
const T = Type.Composite([
|
||||
Type.Object({ x: Type.Optional(Type.Number()) }),
|
||||
Type.Object({ x: Type.Number() })
|
||||
@@ -45,12 +45,119 @@ describe('type/guard/TComposite', () => {
|
||||
Assert.IsFalse(TypeGuard.IsOptional(T.properties.x))
|
||||
Assert.IsTrue(T.required!.includes('x'))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should preserve single optional property', () => {
|
||||
// prettier-ignore
|
||||
const T = Type.Composite([
|
||||
Type.Object({ x: Type.Optional(Type.Number()) }),
|
||||
])
|
||||
Assert.IsTrue(TypeGuard.IsOptional(T.properties.x))
|
||||
Assert.IsEqual(T.required, undefined)
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Intersect
|
||||
// ----------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 1', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ y: Type.Number() }),
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ z: Type.Number() }),
|
||||
])
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.Number(),
|
||||
y: Type.Number(),
|
||||
z: Type.Number()
|
||||
}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 2', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ x: Type.Number() }),
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
])
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.Intersect([Type.Intersect([Type.Number(), Type.Number()]), Type.Number()])
|
||||
}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 3', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Number(),
|
||||
Type.Boolean()
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 4', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Number(),
|
||||
Type.Boolean(),
|
||||
Type.Object({ x: Type.String() })
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.String()
|
||||
}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 5', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Object({ x: Type.Optional(Type.String()) }),
|
||||
Type.Object({ x: Type.String() })
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.Intersect([Type.String(), Type.String()])
|
||||
}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Intersect 6', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Object({ x: Type.Optional(Type.String()) }),
|
||||
Type.Object({ x: Type.Optional(Type.String()) })
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.Optional(Type.Intersect([Type.String(), Type.String()]))
|
||||
}))
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Union
|
||||
// ----------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
it('Should composite Union 1', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Union([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ y: Type.Number() }),
|
||||
]),
|
||||
Type.Union([
|
||||
Type.Object({ z: Type.Number() }),
|
||||
])
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
z: Type.Intersect([Type.Union([Type.Never(), Type.Never()]), Type.Number()])
|
||||
}))
|
||||
})
|
||||
// prettier-ignore
|
||||
it('Should composite Union 2', () => {
|
||||
const T = Type.Composite([
|
||||
Type.Union([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ x: Type.Number() }),
|
||||
]),
|
||||
Type.Union([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
])
|
||||
])
|
||||
Assert.IsEqual(T, Type.Object({
|
||||
x: Type.Intersect([Type.Union([Type.Number(), Type.Number()]), Type.Number()])
|
||||
}))
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,5 +4,6 @@ import './guard/index'
|
||||
import './intrinsic/index'
|
||||
import './normalize/index'
|
||||
import './registry/index'
|
||||
import './sets/index'
|
||||
import './template-literal/index'
|
||||
import './value/index'
|
||||
|
||||
1
test/runtime/type/sets/index.ts
Normal file
1
test/runtime/type/sets/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
import './sets'
|
||||
167
test/runtime/type/sets/sets.ts
Normal file
167
test/runtime/type/sets/sets.ts
Normal file
@@ -0,0 +1,167 @@
|
||||
import * as Type from '@sinclair/typebox'
|
||||
import { Assert } from '../../assert'
|
||||
|
||||
describe('type/sets', () => {
|
||||
// ----------------------------------------------------------------
|
||||
// Distinct
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Distinct', () => {
|
||||
const R = Type.SetDistinct([1, 1, 2, 2])
|
||||
Assert.IsEqual(R, [1, 2])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Includes
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Includes 1', () => {
|
||||
const R = Type.SetIncludes([1, 2, 3, 4], 1)
|
||||
Assert.IsTrue(R)
|
||||
})
|
||||
it('Should Includes 2', () => {
|
||||
const R = Type.SetIncludes([1, 2, 3, 4], 7)
|
||||
Assert.IsFalse(R)
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// IsSubset
|
||||
// ----------------------------------------------------------------
|
||||
it('Should IsSubset 1', () => {
|
||||
const R = Type.SetIsSubset([1, 2], [1, 2])
|
||||
Assert.IsTrue(R)
|
||||
})
|
||||
it('Should IsSubset 2', () => {
|
||||
const R = Type.SetIsSubset([1, 2], [1, 2, 3])
|
||||
Assert.IsTrue(R)
|
||||
})
|
||||
it('Should IsSubset 3', () => {
|
||||
const R = Type.SetIsSubset([1, 2], [1])
|
||||
Assert.IsFalse(R)
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Intersect
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Intersect 1', () => {
|
||||
const R = Type.SetIntersect([1, 2], [1, 2])
|
||||
Assert.IsEqual(R, [1, 2])
|
||||
})
|
||||
it('Should Intersect 2', () => {
|
||||
const R = Type.SetIntersect([1], [1, 2])
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should Intersect 3', () => {
|
||||
const R = Type.SetIntersect([1, 2], [1])
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should Intersect 4', () => {
|
||||
const R = Type.SetIntersect([], [1])
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should Intersect 5', () => {
|
||||
const R = Type.SetIntersect([1], [])
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should Intersect 6', () => {
|
||||
const R = Type.SetIntersect([1], [2])
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Union
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Union 1', () => {
|
||||
const R = Type.SetUnion([1, 2], [1, 2])
|
||||
Assert.IsEqual(R, [1, 2, 1, 2])
|
||||
})
|
||||
it('Should Union 2', () => {
|
||||
const R = Type.SetUnion([1], [1, 2])
|
||||
Assert.IsEqual(R, [1, 1, 2])
|
||||
})
|
||||
it('Should Union 3', () => {
|
||||
const R = Type.SetUnion([1, 2], [1])
|
||||
Assert.IsEqual(R, [1, 2, 1])
|
||||
})
|
||||
it('Should Union 4', () => {
|
||||
const R = Type.SetUnion([], [1])
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should Union 5', () => {
|
||||
const R = Type.SetUnion([1], [])
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// Complement
|
||||
// ----------------------------------------------------------------
|
||||
it('Should Complement 1', () => {
|
||||
const R = Type.SetComplement([1, 2, 3, 4], [2, 3])
|
||||
Assert.IsEqual(R, [1, 4])
|
||||
})
|
||||
it('Should Complement 2', () => {
|
||||
const R = Type.SetComplement([2, 3], [1, 2, 3, 4])
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// IntersectMany
|
||||
// ----------------------------------------------------------------
|
||||
it('Should IntersectMany 1', () => {
|
||||
const R = Type.SetIntersectMany([[1, 2, 3], [1, 2], [1]] as const)
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should IntersectMany 2', () => {
|
||||
const R = Type.SetIntersectMany([[1], [1, 2], [1, 2, 3]] as const)
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should IntersectMany 3', () => {
|
||||
const R = Type.SetIntersectMany([
|
||||
[1, 2],
|
||||
[1, 2],
|
||||
] as const)
|
||||
Assert.IsEqual(R, [1, 2])
|
||||
})
|
||||
it('Should IntersectMany 4', () => {
|
||||
const R = Type.SetIntersectMany([[1], [2]] as const)
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should IntersectMany 5', () => {
|
||||
const R = Type.SetIntersectMany([[1], []] as const)
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should IntersectMany 6', () => {
|
||||
const R = Type.SetIntersectMany([[], [1]] as const)
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should IntersectMany 7', () => {
|
||||
const R = Type.SetIntersectMany([[1], [1], [1], [1], []] as const)
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
it('Should IntersectMany 8', () => {
|
||||
const R = Type.SetIntersectMany([[], [1], [1], [1], [1]] as const)
|
||||
Assert.IsEqual(R, [])
|
||||
})
|
||||
// ----------------------------------------------------------------
|
||||
// UnionMany
|
||||
// ----------------------------------------------------------------
|
||||
it('Should UnionMany 1', () => {
|
||||
const R = Type.SetUnionMany([[1, 2, 3], [1, 2], [1]] as const)
|
||||
Assert.IsEqual(R, [1, 2, 3, 1, 2, 1])
|
||||
})
|
||||
it('Should UnionMany 2', () => {
|
||||
const R = Type.SetUnionMany([[1], [1, 2], [1, 2, 3]] as const)
|
||||
Assert.IsEqual(R, [1, 1, 2, 1, 2, 3])
|
||||
})
|
||||
it('Should UnionMany 3', () => {
|
||||
const R = Type.SetUnionMany([
|
||||
[1, 2],
|
||||
[1, 2],
|
||||
] as const)
|
||||
Assert.IsEqual(R, [1, 2, 1, 2])
|
||||
})
|
||||
it('Should UnionMany 4', () => {
|
||||
const R = Type.SetUnionMany([[1], [2]] as const)
|
||||
Assert.IsEqual(R, [1, 2])
|
||||
})
|
||||
it('Should UnionMany 5', () => {
|
||||
const R = Type.SetUnionMany([[1], []] as const)
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
it('Should UnionMany 6', () => {
|
||||
const R = Type.SetUnionMany([[], [1]] as const)
|
||||
Assert.IsEqual(R, [1])
|
||||
})
|
||||
})
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Expect } from './assert'
|
||||
import { Type, TObject, TIntersect, TNumber, TBoolean } from '@sinclair/typebox'
|
||||
import { Type, TOptional, TObject, TIntersect, TNumber, TBoolean } from '@sinclair/typebox'
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Overlapping - Non Varying
|
||||
@@ -127,3 +127,60 @@ import { Type, TObject, TIntersect, TNumber, TBoolean } from '@sinclair/typebox'
|
||||
Type.Object({ x: Type.Boolean() })
|
||||
])
|
||||
}
|
||||
// ------------------------------------------------------------------
|
||||
// Intersect
|
||||
// ------------------------------------------------------------------
|
||||
// prettier-ignore
|
||||
{
|
||||
const T: TObject<{
|
||||
x: TNumber;
|
||||
y: TNumber;
|
||||
z: TNumber;
|
||||
}> = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ y: Type.Number() }),
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ z: Type.Number() })
|
||||
])
|
||||
])
|
||||
}
|
||||
// prettier-ignore
|
||||
{
|
||||
const T: TObject<{
|
||||
x: TIntersect<[TNumber, TNumber]>;
|
||||
y: TIntersect<[TNumber, TNumber]>;
|
||||
}> = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ y: Type.Number() }),
|
||||
]),
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Number() }),
|
||||
Type.Object({ y: Type.Number() }),
|
||||
])
|
||||
])
|
||||
}
|
||||
// prettier-ignore
|
||||
{
|
||||
const T: TObject<{
|
||||
x: TIntersect<[TNumber, TNumber]>;
|
||||
}> = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Optional(Type.Number()) }),
|
||||
Type.Object({ x: Type.Number() }),
|
||||
])
|
||||
])
|
||||
}
|
||||
// prettier-ignore
|
||||
{
|
||||
const T: TObject<{
|
||||
x: TOptional<TIntersect<[TNumber, TNumber]>>;
|
||||
}> = Type.Composite([
|
||||
Type.Intersect([
|
||||
Type.Object({ x: Type.Optional(Type.Number()) }),
|
||||
Type.Object({ x: Type.Optional(Type.Number()) }),
|
||||
])
|
||||
])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user