diff --git a/example/index.ts b/example/index.ts index 11348e922..b351903b7 100644 --- a/example/index.ts +++ b/example/index.ts @@ -2,34 +2,47 @@ import { TypeSystem } from '@sinclair/typebox/system' import { TypeCompiler } from '@sinclair/typebox/compiler' import { Value, ValuePointer } from '@sinclair/typebox/value' import { Parse, StaticParseAsType } from '@sinclair/typebox/syntax' -import { Type, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' +import { Type, Index, TypeGuard, Kind, Static, TSchema } from '@sinclair/typebox' -// KindGuard.IsLiteralValue - -// New Types: +// Computed Types: // - Awaited (Computed) // - Partial (Computed) // - Pick (Computed) // - Omit (Computed) // - Required (Computed) -// - KeyOf +// - KeyOf (Computed) +// - Index (Computed ... nearly) +// - Record (...) + +const T = Type.Object({ + x: Type.Number(), + y: Type.Number(), + z: Type.Number(), +}) + + + +// const Module = Parse(`module { + +// type A = { +// x: number +// y: number +// z: number +// } + +// type K = A[keyof A] + +// }`) const Module = Type.Module({ A: Type.Object({ x: Type.Number(), - y: Type.Number(), + y: Type.String(), + z: Type.Boolean(), }), - T: Type.KeyOf(Type.Ref('A')), + K: Type.Index(Type.Ref('A'), Type.KeyOf(Type.Ref('A'))) }) -const A = Module.Import('A') -const T = Module.Import('T') - -function test(value: Static) {} - -console.dir(T, { depth: 100 }) - -type A = Static -type T = Static +const K = Module.Import('K') -// Ok(T, { nodes: [{ nodes: [{ nodes: [] }, { nodes: [] }] }] }) +type K = Static diff --git a/src/syntax/runtime.ts b/src/syntax/runtime.ts index 15001ee48..82db79005 100644 --- a/src/syntax/runtime.ts +++ b/src/syntax/runtime.ts @@ -324,11 +324,12 @@ const FactorIndexArray = (Type: Types.TSchema, IndexArray: unknown[]): Types.TSc const [Left, Right] = DestructureRight(IndexArray) as [unknown[], Types.TSchema[]] return ( !Types.ValueGuard.IsUndefined(Right) ? ( - Right.length === 1 ? Types.Index(FactorIndexArray(Type, Left), Right[0]) : + // note: Indexed types require reimplementation to replace `[number]` indexers + Right.length === 1 ? Types.Index(FactorIndexArray(Type, Left), Right[0]) as never : Right.length === 0 ? Types.Array(FactorIndexArray(Type, Left)) : Types.Never() ) : Type - ) + ) } // prettier-ignore const FactorMapping = (KeyOf: boolean, Type: Types.TSchema, IndexArray: unknown[], Extends: Types.TSchema[]) => { diff --git a/src/type/array/array.ts b/src/type/array/array.ts index 388ba25d7..dc29a1858 100644 --- a/src/type/array/array.ts +++ b/src/type/array/array.ts @@ -54,6 +54,6 @@ export interface TArray extends TSchema, ArrayOptio items: T } /** `[Json]` Creates an Array type */ -export function Array(items: T, options?: ArrayOptions): TArray { +export function Array(items: Type, options?: ArrayOptions): TArray { return CreateType({ [Kind]: 'Array', type: 'array', items }, options) as never } diff --git a/src/type/indexed/indexed-from-mapped-key.ts b/src/type/indexed/indexed-from-mapped-key.ts index 4251cea89..b66cf5113 100644 --- a/src/type/indexed/indexed-from-mapped-key.ts +++ b/src/type/indexed/indexed-from-mapped-key.ts @@ -37,68 +37,53 @@ import { Clone } from '../clone/value' // MappedIndexPropertyKey // ------------------------------------------------------------------ // prettier-ignore -type TMappedIndexPropertyKey< - T extends TSchema, - K extends PropertyKey -> = { - [_ in K]: TIndex +type TMappedIndexPropertyKey = { + [_ in Key]: TIndex } // prettier-ignore -function MappedIndexPropertyKey< - T extends TSchema, - K extends PropertyKey ->(T: T, K: K, options?: SchemaOptions): TMappedIndexPropertyKey { - return { [K]: Index(T, [K], Clone(options)) } as never +function MappedIndexPropertyKey(type: Type, key: Key, options?: SchemaOptions): TMappedIndexPropertyKey { + return { [key]: Index(type, [key], Clone(options)) } as never } // ------------------------------------------------------------------ // MappedIndexPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -type TMappedIndexPropertyKeys = ( - K extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] - ? TMappedIndexPropertyKeys> - : Acc +type TMappedIndexPropertyKeys = ( + PropertyKeys extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] + ? TMappedIndexPropertyKeys> + : Result ) // prettier-ignore -function MappedIndexPropertyKeys< - T extends TSchema, - K extends PropertyKey[] ->(T: T, K: [...K], options?: SchemaOptions): TMappedIndexPropertyKeys { - return K.reduce((Acc, L) => { - return { ...Acc, ...MappedIndexPropertyKey(T, L, options) } +function MappedIndexPropertyKeys(type: Type, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TMappedIndexPropertyKeys { + return propertyKeys.reduce((result, left) => { + return { ...result, ...MappedIndexPropertyKey(type, left, options) } }, {} as TProperties) as never } // ------------------------------------------------------------------ // MappedIndexProperties // ------------------------------------------------------------------ // prettier-ignore -type TMappedIndexProperties = Evaluate< - TMappedIndexPropertyKeys +type TMappedIndexProperties = Evaluate< + TMappedIndexPropertyKeys > // prettier-ignore -function MappedIndexProperties< - T extends TSchema, - K extends TMappedKey ->(T: T, K: K, options?: SchemaOptions): TMappedIndexProperties { - return MappedIndexPropertyKeys(T, K.keys, options) as never +function MappedIndexProperties(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedIndexProperties { + return MappedIndexPropertyKeys(type, mappedKey.keys, options) as never } // ------------------------------------------------------------------ // TIndexFromMappedKey // ------------------------------------------------------------------ // prettier-ignore -export type TIndexFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TMappedIndexProperties +export type TIndexFromMappedKey > = ( - Ensure> + Ensure> ) // prettier-ignore -export function IndexFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TMappedIndexProperties ->(T: T, K: K, options?: SchemaOptions): TMappedResult

{ - const P = MappedIndexProperties(T, K, options) - return MappedResult(P) as never +export function IndexFromMappedKey +>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedResult { + const properties = MappedIndexProperties(type, mappedKey, options) + return MappedResult(properties) as never } diff --git a/src/type/indexed/indexed-from-mapped-result.ts b/src/type/indexed/indexed-from-mapped-result.ts index d23fa750d..136e7a1ba 100644 --- a/src/type/indexed/indexed-from-mapped-result.ts +++ b/src/type/indexed/indexed-from-mapped-result.ts @@ -37,21 +37,22 @@ import { Index, type TIndex } from './index' // ------------------------------------------------------------------ // prettier-ignore type TFromProperties< - T extends TSchema, - P extends TProperties + Type extends TSchema, + Properties extends TProperties > = ( - { [K2 in keyof P]: TIndex> } + { [K2 in keyof Properties]: TIndex> } ) // prettier-ignore function FromProperties< - T extends TSchema, - P extends TProperties ->(T: T, P: P, options?: SchemaOptions): TFromProperties { - const Acc = {} as Record - for(const K2 of Object.getOwnPropertyNames(P)) { - Acc[K2] = Index(T, IndexPropertyKeys(P[K2]), options) + Type extends TSchema, + Properties extends TProperties +>(type: Type, properties: Properties, options?: SchemaOptions): TFromProperties { + const result = {} as Record + for(const K2 of Object.getOwnPropertyNames(properties)) { + const keys = IndexPropertyKeys(properties[K2]) + result[K2] = Index(type, keys, options) as never } - return Acc as never + return result as never } // ------------------------------------------------------------------ // FromMappedResult diff --git a/src/type/indexed/indexed-property-keys.ts b/src/type/indexed/indexed-property-keys.ts index dcb60fad7..ad73541e4 100644 --- a/src/type/indexed/indexed-property-keys.ts +++ b/src/type/indexed/indexed-property-keys.ts @@ -41,38 +41,40 @@ import { IsTemplateLiteral, IsUnion, IsLiteral, IsNumber, IsInteger } from '../g // FromTemplateLiteral // ------------------------------------------------------------------ // prettier-ignore -type TFromTemplateLiteral> = (R) +type TFromTemplateLiteral +> = Result // prettier-ignore -function FromTemplateLiteral(T: T): TFromTemplateLiteral { - const R = TemplateLiteralGenerate(T) as string[] - return R.map(S => S.toString()) as never +function FromTemplateLiteral(templateLiteral: TemplateLiteral): TFromTemplateLiteral { + const result = TemplateLiteralGenerate(templateLiteral) as string[] + return result.map(S => S.toString()) as never } // ------------------------------------------------------------------ // FromUnion // ------------------------------------------------------------------ // prettier-ignore -type TFromUnion = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromUnion]> - : Acc +type TFromUnion = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? TFromUnion]> + : Result ) // prettier-ignore -function FromUnion(T: T): TFromUnion { - const Acc = [] as string[] - for(const L of T) Acc.push(...IndexPropertyKeys(L)) - return Acc as never +function FromUnion(type: Type): TFromUnion { + const result = [] as string[] + for(const left of type) result.push(...IndexPropertyKeys(left)) + return result as never } // ------------------------------------------------------------------ // FromLiteral // ------------------------------------------------------------------ // prettier-ignore -type TFromLiteral = ( - T extends PropertyKey - ? [`${T}`] +type TFromLiteral = ( + LiteralValue extends PropertyKey + ? [`${LiteralValue}`] : [] ) // prettier-ignore -function FromLiteral(T: T): TFromLiteral { +function FromLiteral(T: LiteralValue): TFromLiteral { return ( [(T as string).toString()] // TS 5.4 observes TLiteralValue as not having a toString() ) as never @@ -81,23 +83,23 @@ function FromLiteral(T: T): TFromLiteral { // IndexedKeyResolve // ------------------------------------------------------------------ // prettier-ignore -export type TIndexPropertyKeys = ( - T extends TTemplateLiteral ? TFromTemplateLiteral : - T extends TUnion ? TFromUnion : - T extends TLiteral ? TFromLiteral : - T extends TNumber ? ['[number]'] : - T extends TInteger ? ['[number]'] : +export type TIndexPropertyKeys : + Type extends TUnion ? TFromUnion : + Type extends TLiteral ? TFromLiteral : + Type extends TNumber ? ['[number]'] : + Type extends TInteger ? ['[number]'] : [] -) +)> = Result /** Returns a tuple of PropertyKeys derived from the given TSchema */ // prettier-ignore -export function IndexPropertyKeys(T: T): TIndexPropertyKeys { +export function IndexPropertyKeys(type: Type): TIndexPropertyKeys { return [...new Set(( - IsTemplateLiteral(T) ? FromTemplateLiteral(T) : - IsUnion(T) ? FromUnion(T.anyOf) : - IsLiteral(T) ? FromLiteral(T.const) : - IsNumber(T) ? ['[number]'] : - IsInteger(T) ? ['[number]'] : + IsTemplateLiteral(type) ? FromTemplateLiteral(type) : + IsUnion(type) ? FromUnion(type.anyOf) : + IsLiteral(type) ? FromLiteral(type.const) : + IsNumber(type) ? ['[number]'] : + IsInteger(type) ? ['[number]'] : [] ))] as never } diff --git a/src/type/indexed/indexed.ts b/src/type/indexed/indexed.ts index 6de947666..656a19cc5 100644 --- a/src/type/indexed/indexed.ts +++ b/src/type/indexed/indexed.ts @@ -28,62 +28,93 @@ THE SOFTWARE. import { CreateType } from '../create/type' import { type TSchema, SchemaOptions } from '../schema/index' +import { Computed, type TComputed } from '../computed/index' +import { Literal, type TLiteral, type TLiteralValue } from '../literal/index' import { type TObject, type TProperties } from '../object/index' -import { type Assert } from '../helpers/index' +import { type Ensure, type Assert } from '../helpers/index' import { Never, type TNever } from '../never/index' import { type TRecursive } from '../recursive/index' import { type TIntersect } from '../intersect/index' import { TMappedResult, type TMappedKey } from '../mapped/index' -import { type TUnion } from '../union/index' +import { Union, type TUnion } from '../union/index' import { type TTuple } from '../tuple/index' import { type TArray } from '../array/index' +import { Ref, type TRef } from '../ref/index' import { IntersectEvaluated, type TIntersectEvaluated } from '../intersect/index' import { UnionEvaluated, type TUnionEvaluated } from '../union/index' +// ------------------------------------------------------------------ +// Infrastructure +// ------------------------------------------------------------------ import { IndexPropertyKeys, type TIndexPropertyKeys } from './indexed-property-keys' import { IndexFromMappedKey, type TIndexFromMappedKey } from './indexed-from-mapped-key' import { IndexFromMappedResult, type TIndexFromMappedResult } from './indexed-from-mapped-result' + +// ------------------------------------------------------------------ +// KindGuard // ------------------------------------------------------------------ -// TypeGuard +import { IsArray, IsIntersect, IsObject, IsMappedKey, IsMappedResult, IsNever, IsSchema, IsTuple, IsUnion, IsLiteralValue, IsRef, IsComputed } from '../guard/kind' +import { IsArray as IsArrayValue } from '../guard/value' + +// ------------------------------------------------------------------ +// FromComputed // ------------------------------------------------------------------ -import { IsArray, IsIntersect, IsObject, IsMappedKey, IsMappedResult, IsNever, IsSchema, IsTuple, IsUnion } from '../guard/kind' +// prettier-ignore +// type TFromComputed = Ensure< +// TComputed<'Partial', [TComputed]> +// > +// // prettier-ignore +// function FromComputed(target: Target, parameters: Parameters): TFromComputed { +// return Computed('Partial', [Computed(target, parameters)]) as never +// } +// // ------------------------------------------------------------------ +// // FromRef +// // ------------------------------------------------------------------ +// // prettier-ignore +// type TFromRef = Ensure< +// TComputed<'Partial', [TRef]> +// > +// // prettier-ignore +// function FromRef($ref: Ref): TFromRef { +// return Computed('Partial', [Ref($ref)]) as never +// } // ------------------------------------------------------------------ // FromRest // ------------------------------------------------------------------ // prettier-ignore -type TFromRest = ( +type TFromRest = ( T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest, TSchema>]> - : Acc + ? TFromRest, TSchema>]> + : Result ) // prettier-ignore -function FromRest(T: [...T], K: K): TFromRest { - return T.map(L => IndexFromPropertyKey(L, K)) as never +function FromRest(types: [...Types], key: K): TFromRest { + return types.map(left => IndexFromPropertyKey(left, key)) as never } // ------------------------------------------------------------------ // FromIntersectRest // ------------------------------------------------------------------ // prettier-ignore -type TFromIntersectRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? L extends TNever - ? TFromIntersectRest - : TFromIntersectRest - : Acc +type TFromIntersectRest = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TNever + ? TFromIntersectRest + : TFromIntersectRest + : Result ) // prettier-ignore -function FromIntersectRest(T: [...T]): TFromIntersectRest { - return T.filter(L => !IsNever(L)) as never +function FromIntersectRest(types: [...Types]): TFromIntersectRest { + return types.filter(left => !IsNever(left)) as never } // prettier-ignore -type TFromIntersect = ( - TIntersectEvaluated>> +type TFromIntersect = ( + TIntersectEvaluated>> ) // prettier-ignore -function FromIntersect(T: [...T], K: K): TFromIntersect { +function FromIntersect(types: [...Types], key: Key): TFromIntersect { return ( - IntersectEvaluated(FromIntersectRest(FromRest(T as TSchema[], K))) + IntersectEvaluated(FromIntersectRest(FromRest(types as TSchema[], key))) ) as never } // ------------------------------------------------------------------ @@ -110,47 +141,51 @@ function FromIntersect(T: [...T], K: // // ------------------------------------------------------------------ // prettier-ignore -type TFromUnionRest = - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? L extends TNever +type TFromUnionRest = + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TNever ? [] - : TFromUnionRest - : Acc + : TFromUnionRest + : Result // prettier-ignore -function FromUnionRest(T: [...T]): TFromUnionRest { +function FromUnionRest(types: [...Types]): TFromUnionRest { return ( - T.some(L => IsNever(L)) + types.some(L => IsNever(L)) ? [] - : T + : types ) as never } // ------------------------------------------------------------------ // FromUnion // ------------------------------------------------------------------ // prettier-ignore -type TFromUnion = ( - TUnionEvaluated>> +type TFromUnion = ( + TUnionEvaluated>> ) // prettier-ignore -function FromUnion(T: [...T], K: K): TFromUnion { +function FromUnion(types: [...Types], key: Key): TFromUnion { return ( - UnionEvaluated(FromUnionRest(FromRest(T as TSchema[], K))) + UnionEvaluated(FromUnionRest(FromRest(types as TSchema[], key))) ) as never } // ------------------------------------------------------------------ // FromTuple // ------------------------------------------------------------------ + // prettier-ignore -type TFromTuple = ( - K extends keyof T ? T[K] : - K extends '[number]' ? TUnionEvaluated : - TNever -) +type TFromTuple : + Key extends keyof Types + ? Types[Key] extends infer Type extends TSchema + ? Type + : TNever + : TNever +)> = Result // prettier-ignore -function FromTuple(T: [...T], K: K): TFromTuple { +function FromTuple(types: [...Types], key: Key): TFromTuple { return ( - K in T ? T[K as number] : - K === '[number]' ? UnionEvaluated(T) : + key === '[number]' ? UnionEvaluated(types) : + key in types ? types[key as number] : Never() ) as never } @@ -158,62 +193,54 @@ function FromTuple(T: [...T], K: K): // FromArray // ------------------------------------------------------------------ // prettier-ignore -type TFromArray = ( - K extends '[number]' - ? T - : TNever +type TFromArray = ( + Key extends '[number]' ? Type : TNever ) // prettier-ignore -function FromArray(T: T, K: K): TFromArray { - return ( - K === '[number]' - ? T - : Never() - ) as never +function FromArray(type: Type, key: Key): TFromArray { + // ... ? + return (key === '[number]' ? type : Never()) as never } // ------------------------------------------------------------------ // FromProperty // ------------------------------------------------------------------ -type AssertPropertyKey = Assert +type AssertPropertyKey = Assert // prettier-ignore -type TFromProperty< - T extends TProperties, - K extends PropertyKey, -> = ( +type TFromProperty}` extends `${AssertPropertyKey}` - ? T[AssertPropertyKey] + : `${AssertPropertyKey}` extends `${AssertPropertyKey}` + ? Properties[AssertPropertyKey] : TNever -) +)> = Result // prettier-ignore -function FromProperty(T: T, K: K): TFromProperty { - return (K in T ? T[K as string] : Never()) as never +function FromProperty(properties: Properties, key: Key): TFromProperty { + return (key in properties ? properties[key as string] : Never()) as never } // ------------------------------------------------------------------ // FromKey // ------------------------------------------------------------------ // prettier-ignore -export type TIndexFromPropertyKey = ( - T extends TRecursive ? TIndexFromPropertyKey : - T extends TIntersect ? TFromIntersect : - T extends TUnion ? TFromUnion : - T extends TTuple ? TFromTuple : - T extends TArray ? TFromArray : - T extends TObject ? TFromProperty : +export type TIndexFromPropertyKey = ( + Type extends TRecursive ? TIndexFromPropertyKey : + Type extends TIntersect ? TFromIntersect : + Type extends TUnion ? TFromUnion : + Type extends TTuple ? TFromTuple : + Type extends TArray ? TFromArray : + Type extends TObject ? TFromProperty : TNever ) // prettier-ignore -export function IndexFromPropertyKey(T: T, K: K): TIndexFromPropertyKey { +export function IndexFromPropertyKey(type: Type, key: Key): TIndexFromPropertyKey { return ( - IsIntersect(T) ? FromIntersect(T.allOf, K) : - IsUnion(T) ? FromUnion(T.anyOf, K) : - IsTuple(T) ? FromTuple(T.items ?? [], K) : - IsArray(T) ? FromArray(T.items, K) : - IsObject(T) ? FromProperty(T.properties, K) : + IsIntersect(type) ? FromIntersect(type.allOf, key) : + IsUnion(type) ? FromUnion(type.anyOf, key) : + IsTuple(type) ? FromTuple(type.items ?? [], key) : + IsArray(type) ? FromArray(type.items, key) : + IsObject(type) ? FromProperty(type.properties, key) : Never() ) as never } @@ -221,52 +248,81 @@ export function IndexFromPropertyKey(T // FromKeys // ------------------------------------------------------------------ // prettier-ignore -export type TIndexFromPropertyKeys = ( - K extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] - ? TIndexFromPropertyKeys, TSchema>]> - : Acc +export type TIndexFromPropertyKeys = ( + PropertyKeys extends [infer Left extends PropertyKey, ...infer Right extends PropertyKey[]] + ? TIndexFromPropertyKeys, TSchema>]> + : Result ) // prettier-ignore -export function IndexFromPropertyKeys(T: T, K: [...K]): TIndexFromPropertyKeys { - return K.map(L => IndexFromPropertyKey(T, L)) as never +export function IndexFromPropertyKeys(type: Type, propertyKeys: [...PropertyKeys]): TIndexFromPropertyKeys { + return propertyKeys.map(left => IndexFromPropertyKey(type, left)) as never } // ------------------------------------------------------------------ // FromSchema // ------------------------------------------------------------------ // prettier-ignore -type FromSchema = ( - TUnionEvaluated> +type TFromType, +> = TUnionEvaluated +// prettier-ignore +function FromType(type: Type, propertyKeys: [...PropertyKeys]): TFromType { + const result = IndexFromPropertyKeys(type, propertyKeys as PropertyKey[]) + return UnionEvaluated(result) as never +} +// ------------------------------------------------------------------ +// UnionFromPropertyKeys +// ------------------------------------------------------------------ +// prettier-ignore +type TUnionFromPropertyKeys = ( + PropertyKeys extends [infer Key extends PropertyKey, ...infer Rest extends PropertyKey[]] + ? Key extends TLiteralValue + ? TUnionFromPropertyKeys]> + : TUnionFromPropertyKeys + : TUnionEvaluated ) // prettier-ignore -function FromSchema(T: T, K: [...K]): FromSchema { - return ( - UnionEvaluated(IndexFromPropertyKeys(T, K as PropertyKey[])) - ) as never +function UnionFromPropertyKeys(propertyKeys: PropertyKeys): TUnionFromPropertyKeys { + const result = propertyKeys.reduce((result, key) => IsLiteralValue(key) ? [...result, Literal(key)]: result, [] as TLiteral[]) + return UnionEvaluated(result) as never } // ------------------------------------------------------------------ // TIndex // ------------------------------------------------------------------ // prettier-ignore -export type TIndex = ( - FromSchema +export type TIndex : Key, + PropertyKeys extends PropertyKey[] = Key extends TSchema ? TIndexPropertyKeys : Key, + IsTypeRef extends boolean = Type extends TRef ? true : false, + IsKeyRef extends boolean = Key extends TRef ? true : false, +> = ( + Key extends TMappedResult ? TIndexFromMappedResult : + Key extends TMappedKey ? TIndexFromMappedKey : + [IsTypeRef, IsKeyRef] extends [true, true] ? TComputed<'Index', [Type, TypeKey]> : + [IsTypeRef, IsKeyRef] extends [false, true] ? TComputed<'Index', [Type, TypeKey]> : + [IsTypeRef, IsKeyRef] extends [true, false] ? TComputed<'Index', [Type, TypeKey]> : + TFromType ) /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index(T: T, K: K, options?: SchemaOptions): TIndexFromMappedResult +export function Index(type: Type, key: readonly [...Key], options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index(T: T, K: K, options?: SchemaOptions): TIndexFromMappedKey +export function Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index>(T: T, K: K, options?: SchemaOptions): TIndex +export function Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index(T: T, K: readonly [...K], options?: SchemaOptions): TIndex +export function Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index(T: TSchema, K: any, options?: SchemaOptions): any { - // mapped-types - if (IsMappedResult(K)) return IndexFromMappedResult(T, K, options) - if (IsMappedKey(K)) return IndexFromMappedKey(T, K, options) - // prettier-ignore - return CreateType( - IsSchema(K) - ? FromSchema(T, IndexPropertyKeys(K)) - : FromSchema(T, K as string[]) - , options) as never +// prettier-ignore +export function Index(type: any, key: any, options?: SchemaOptions): any { + const typeKey: TSchema = IsArrayValue(key) ? UnionFromPropertyKeys(key as PropertyKey[]) : key + const propertyKeys: PropertyKey[] = IsSchema(key) ? IndexPropertyKeys(key) : key + const isTypeRef: boolean = IsRef(type) + const isKeyRef: boolean = IsRef(key) + return ( + IsMappedResult(key) ? IndexFromMappedResult(type, key, options) : + IsMappedKey(key) ? IndexFromMappedKey(type, key, options) : + (isTypeRef && isKeyRef) ? Computed('Index', [type, typeKey], options) : + (!isTypeRef && isKeyRef) ? Computed('Index', [type, typeKey], options) : + (isTypeRef && !isKeyRef) ? Computed('Index', [type, typeKey], options) : + CreateType(FromType(type, propertyKeys), options) + ) as never } diff --git a/src/type/intersect/intersect-evaluated.ts b/src/type/intersect/intersect-evaluated.ts index a0c73484b..637009345 100644 --- a/src/type/intersect/intersect-evaluated.ts +++ b/src/type/intersect/intersect-evaluated.ts @@ -46,77 +46,77 @@ import { IsOptional, IsTransform } from '../guard/kind' // IsIntersectOptional // ------------------------------------------------------------------ // prettier-ignore -type TIsIntersectOptional = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? L extends TOptional - ? TIsIntersectOptional +type TIsIntersectOptional = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TOptional + ? TIsIntersectOptional : false : true ) // prettier-ignore -function IsIntersectOptional(T: T): TIsIntersectOptional { - return T.every(L => IsOptional(L)) as never +function IsIntersectOptional(types: [...Types]): TIsIntersectOptional { + return types.every(left => IsOptional(left)) as never } // ------------------------------------------------------------------ // RemoveOptionalFromType // ------------------------------------------------------------------ // prettier-ignore -type TRemoveOptionalFromType = ( - T extends TReadonly ? TReadonly> : - T extends TOptional ? TRemoveOptionalFromType : - T +type TRemoveOptionalFromType = ( + Type extends TReadonly ? TReadonly> : + Type extends TOptional ? TRemoveOptionalFromType : + Type ) // prettier-ignore -function RemoveOptionalFromType(T: T): TRemoveOptionalFromType { +function RemoveOptionalFromType(type: Type): TRemoveOptionalFromType { return ( - Discard(T, [OptionalKind]) + Discard(type, [OptionalKind]) ) as never } // ------------------------------------------------------------------ // RemoveOptionalFromRest // ------------------------------------------------------------------ // prettier-ignore -type TRemoveOptionalFromRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? L extends TOptional - ? TRemoveOptionalFromRest]> - : TRemoveOptionalFromRest - : Acc +type TRemoveOptionalFromRest = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TOptional + ? TRemoveOptionalFromRest]> + : TRemoveOptionalFromRest + : Result ) // prettier-ignore -function RemoveOptionalFromRest(T: T): TRemoveOptionalFromRest { - return T.map(L => IsOptional(L) ? RemoveOptionalFromType(L) : L) as never +function RemoveOptionalFromRest(types: [...Types]): TRemoveOptionalFromRest { + return types.map(left => IsOptional(left) ? RemoveOptionalFromType(left) : left) as never } // ------------------------------------------------------------------ // ResolveIntersect // ------------------------------------------------------------------ // prettier-ignore -type TResolveIntersect = ( - TIsIntersectOptional extends true - ? TOptional>> - : TIntersect> +type TResolveIntersect = ( + TIsIntersectOptional extends true + ? TOptional>> + : TIntersect> ) // prettier-ignore -function ResolveIntersect(T: [...T], options: SchemaOptions): TResolveIntersect { +function ResolveIntersect(types: [...Types], options: SchemaOptions): TResolveIntersect { return ( - IsIntersectOptional(T) - ? Optional(IntersectCreate(RemoveOptionalFromRest(T) as TSchema[], options)) - : IntersectCreate(RemoveOptionalFromRest(T) as TSchema[], options) + IsIntersectOptional(types) + ? Optional(IntersectCreate(RemoveOptionalFromRest(types) as TSchema[], options)) + : IntersectCreate(RemoveOptionalFromRest(types) as TSchema[], options) ) as never } // ------------------------------------------------------------------ // IntersectEvaluated // ------------------------------------------------------------------ // prettier-ignore -export type TIntersectEvaluated = ( - T extends [] ? TNever : - T extends [TSchema] ? T[0] : - TResolveIntersect +export type TIntersectEvaluated = ( + Types extends [TSchema] ? Types[0] : + Types extends [] ? TNever : + TResolveIntersect ) /** `[Json]` Creates an evaluated Intersect type */ -export function IntersectEvaluated>(T: [...T], options: IntersectOptions = {}): R { - if (T.length === 0) return Never(options) as never - if (T.length === 1) return CreateType(T[0], options) as never - if (T.some((schema) => IsTransform(schema))) throw new Error('Cannot intersect transform types') - return ResolveIntersect(T, options) as never +export function IntersectEvaluated>(types: [...Types], options: IntersectOptions = {}): Result { + if (types.length === 1) return CreateType(types[0], options) as never + if (types.length === 0) return Never(options) as never + if (types.some((schema) => IsTransform(schema))) throw new Error('Cannot intersect transform types') + return ResolveIntersect(types, options) as never } diff --git a/src/type/intersect/intersect.ts b/src/type/intersect/intersect.ts index 66275057f..999d3d2af 100644 --- a/src/type/intersect/intersect.ts +++ b/src/type/intersect/intersect.ts @@ -40,15 +40,15 @@ import { IsTransform } from '../guard/kind' // Intersect // ------------------------------------------------------------------ // prettier-ignore -export type Intersect = ( - T extends [] ? TNever : - T extends [TSchema] ? T[0] : - TIntersect +export type Intersect = ( + Types extends [TSchema] ? Types[0] : + Types extends [] ? TNever : + TIntersect ) /** `[Json]` Creates an evaluated Intersect type */ -export function Intersect(T: [...T], options?: IntersectOptions): Intersect { - if (T.length === 0) return Never(options) as never - if (T.length === 1) return CreateType(T[0], options) as never - if (T.some((schema) => IsTransform(schema))) throw new Error('Cannot intersect transform types') - return IntersectCreate(T, options) as never +export function Intersect(types: [...Types], options?: IntersectOptions): Intersect { + if (types.length === 1) return CreateType(types[0], options) as never + if (types.length === 0) return Never(options) as never + if (types.some((schema) => IsTransform(schema))) throw new Error('Cannot intersect transform types') + return IntersectCreate(types, options) as never } diff --git a/src/type/module/compute.ts b/src/type/module/compute.ts index ed4f42991..8fdd7b868 100644 --- a/src/type/module/compute.ts +++ b/src/type/module/compute.ts @@ -35,6 +35,7 @@ import { Awaited, type TAwaited } from '../awaited/index' import { AsyncIterator, type TAsyncIterator } from '../async-iterator/index' import { TComputed } from '../computed/index' import { Constructor, type TConstructor } from '../constructor/index' +import { Index, type TIndex } from '../indexed/index' import { Function, type TFunction } from '../function/index' import { Intersect, type TIntersect, type TIntersectEvaluated } from '../intersect/index' import { Iterator, type TIterator } from '../iterator/index' @@ -109,6 +110,17 @@ function FromAwaited(parameters: Parameters): TFro return Awaited(parameters[0]) as never } // ------------------------------------------------------------------ +// Index +// ------------------------------------------------------------------ +// prettier-ignore +type TFromIndex = ( + Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] ? TIndex : never +) +// prettier-ignore +function FromIndex(parameters: Parameters): TFromIndex { + return Index(parameters[0], parameters[1]) as never +} +// ------------------------------------------------------------------ // KeyOf // ------------------------------------------------------------------ // prettier-ignore @@ -171,6 +183,7 @@ type TFromComputed > = ( Target extends 'Awaited' ? TFromAwaited : + Target extends 'Index' ? TFromIndex : Target extends 'KeyOf' ? TFromKeyOf : Target extends 'Partial' ? TFromPartial : Target extends 'Omit' ? TFromOmit : @@ -183,6 +196,7 @@ function FromComputed(moduleProperties: ModuleProperties, properties: Properties): TFromObject { return Object( globalThis.Object.keys(properties).reduce((result, key) => { - return { ...result, [key]: FromType(moduleProperties, properties[key]) as TSchema } + return { ...result, [key]: FromType(moduleProperties, properties[key]) as never } }, {} as TProperties), ) as never } @@ -218,7 +232,7 @@ function FromConstructor { - return Constructor(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, instanceType)) as never + return Constructor(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, instanceType) as never) as never } // ------------------------------------------------------------------ // Function @@ -233,7 +247,7 @@ function FromFunction { - return Function(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, returnType)) as never + return Function(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, returnType) as never) as never } // ------------------------------------------------------------------ // Tuple @@ -327,7 +341,10 @@ export type TFromType(moduleProperties: ModuleProperties, type: Type): TFromType { return ( - KindGuard.IsComputed(type) ? CreateType(FromComputed(moduleProperties, type.target, type.parameters)) : + // Note: The 'as never' is required due to excessive resolution of TIndex. In fact TIndex, TPick, TOmit and + // all need re-implementation to remove the PropertyKey[] selector. Reimplementation of these types should + // be a priority as there is a potential for the current inference to break on TS compiler changes. + KindGuard.IsComputed(type) ? CreateType(FromComputed(moduleProperties, type.target, type.parameters) as never) : KindGuard.IsObject(type) ? CreateType(FromObject(moduleProperties, type.properties), type) : KindGuard.IsConstructor(type) ? CreateType(FromConstructor(moduleProperties, type.parameters, type.returns), type) : KindGuard.IsFunction(type) ? CreateType(FromFunction(moduleProperties, type.parameters, type.returns), type) : diff --git a/src/type/not/not.ts b/src/type/not/not.ts index 256a3c8eb..eb283dfdf 100644 --- a/src/type/not/not.ts +++ b/src/type/not/not.ts @@ -37,6 +37,6 @@ export interface TNot extends TSchema { not: T } /** `[Json]` Creates a Not type */ -export function Not(not: T, options?: SchemaOptions): TNot { - return CreateType({ [Kind]: 'Not', not }, options) as never +export function Not(type: Type, options?: SchemaOptions): TNot { + return CreateType({ [Kind]: 'Not', not: type }, options) as never } diff --git a/src/type/required/required.ts b/src/type/required/required.ts index de51d42bb..7ae6a234d 100644 --- a/src/type/required/required.ts +++ b/src/type/required/required.ts @@ -141,7 +141,7 @@ export type TRequired = ( TObject<{}> ) /** `[Json]` Constructs a type where all properties are required */ -export function Required(mappedResult: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult +export function Required(type: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult /** `[Json]` Constructs a type where all properties are required */ export function Required(type: Type, options?: SchemaOptions): TRequired /** `[Json]` Constructs a type where all properties are required */ diff --git a/src/type/tuple/tuple.ts b/src/type/tuple/tuple.ts index 67d564f9d..80b092c79 100644 --- a/src/type/tuple/tuple.ts +++ b/src/type/tuple/tuple.ts @@ -52,11 +52,11 @@ export interface TTuple extends TSchema { maxItems: number } /** `[Json]` Creates a Tuple type */ -export function Tuple(items: [...T], options?: SchemaOptions): TTuple { +export function Tuple(types: [...Types], options?: SchemaOptions): TTuple { // prettier-ignore return CreateType( - items.length > 0 ? - { [Kind]: 'Tuple', type: 'array', items, additionalItems: false, minItems: items.length, maxItems: items.length } : - { [Kind]: 'Tuple', type: 'array', minItems: items.length, maxItems: items.length }, + types.length > 0 ? + { [Kind]: 'Tuple', type: 'array', items: types, additionalItems: false, minItems: types.length, maxItems: types.length } : + { [Kind]: 'Tuple', type: 'array', minItems: types.length, maxItems: types.length }, options) as never } diff --git a/src/type/type/javascript.ts b/src/type/type/javascript.ts index fad81ea22..101231eb2 100644 --- a/src/type/type/javascript.ts +++ b/src/type/type/javascript.ts @@ -49,11 +49,11 @@ import { Void, type TVoid } from '../void/index' /** JavaScript Type Builder with Static Resolution for TypeScript */ export class JavaScriptTypeBuilder extends JsonTypeBuilder { /** `[JavaScript]` Creates a AsyncIterator type */ - public AsyncIterator(items: T, options?: SchemaOptions): TAsyncIterator { + public AsyncIterator(items: Type, options?: SchemaOptions): TAsyncIterator { return AsyncIterator(items, options) } /** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */ - public Awaited(schema: T, options?: SchemaOptions): TAwaited { + public Awaited(schema: Type, options?: SchemaOptions): TAwaited { return Awaited(schema, options) } /** `[JavaScript]` Creates a BigInt type */ @@ -61,35 +61,35 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { return BigInt(options) } /** `[JavaScript]` Extracts the ConstructorParameters from the given Constructor type */ - public ConstructorParameters>(schema: T, options?: SchemaOptions): TConstructorParameters { + public ConstructorParameters(schema: Type, options?: SchemaOptions): TConstructorParameters { return ConstructorParameters(schema, options) } /** `[JavaScript]` Creates a Constructor type */ - public Constructor(parameters: [...T], returns: U, options?: SchemaOptions): TConstructor { - return Constructor(parameters, returns, options) + public Constructor(parameters: [...Parameters], instanceType: InstanceType, options?: SchemaOptions): TConstructor { + return Constructor(parameters, instanceType, options) } /** `[JavaScript]` Creates a Date type */ public Date(options: DateOptions = {}): TDate { return Date(options) } /** `[JavaScript]` Creates a Function type */ - public Function(parameters: [...T], returns: U, options?: SchemaOptions): TFunction { - return FunctionType(parameters, returns, options) + public Function(parameters: [...Parameters], returnType: ReturnType, options?: SchemaOptions): TFunction { + return FunctionType(parameters, returnType, options) } /** `[JavaScript]` Extracts the InstanceType from the given Constructor type */ - public InstanceType>(schema: T, options?: SchemaOptions): TInstanceType { + public InstanceType(schema: Type, options?: SchemaOptions): TInstanceType { return InstanceType(schema, options) } /** `[JavaScript]` Creates an Iterator type */ - public Iterator(items: T, options?: SchemaOptions): TIterator { + public Iterator(items: Type, options?: SchemaOptions): TIterator { return Iterator(items, options) } /** `[JavaScript]` Extracts the Parameters from the given Function type */ - public Parameters>(schema: T, options?: SchemaOptions): TParameters { + public Parameters(schema: Type, options?: SchemaOptions): TParameters { return Parameters(schema, options) } /** `[JavaScript]` Creates a Promise type */ - public Promise(item: T, options?: SchemaOptions): TPromise { + public Promise(item: Type, options?: SchemaOptions): TPromise { return Promise(item, options) } /** `[JavaScript]` Creates a RegExp type */ @@ -101,8 +101,8 @@ export class JavaScriptTypeBuilder extends JsonTypeBuilder { return RegExp(unresolved as any, options) } /** `[JavaScript]` Extracts the ReturnType from the given Function type */ - public ReturnType>(schema: T, options?: SchemaOptions): TReturnType { - return ReturnType(schema, options) + public ReturnType(type: Type, options?: SchemaOptions): TReturnType { + return ReturnType(type, options) } /** `[JavaScript]` Creates a Symbol type */ public Symbol(options?: SchemaOptions): TSymbol { diff --git a/src/type/type/json.ts b/src/type/type/json.ts index 6a4bde307..acc91ce1f 100644 --- a/src/type/type/json.ts +++ b/src/type/type/json.ts @@ -75,32 +75,32 @@ export class JsonTypeBuilder { // Modifiers // ------------------------------------------------------------------------ /** `[Json]` Creates a Readonly and Optional property */ - public ReadonlyOptional(schema: T): TReadonlyOptional { - return ReadonlyOptional(schema) + public ReadonlyOptional(type: Type): TReadonlyOptional { + return ReadonlyOptional(type) } /** `[Json]` Creates a Readonly property */ - public Readonly(schema: T, enable: F): TReadonlyFromMappedResult + public Readonly(type: Type, enable: Flag): TReadonlyFromMappedResult /** `[Json]` Creates a Readonly property */ - public Readonly(schema: T, enable: F): TReadonlyWithFlag + public Readonly(type: Type, enable: Flag): TReadonlyWithFlag /** `[Json]` Creates a Optional property */ - public Readonly(schema: T): TReadonlyFromMappedResult + public Readonly(type: Type): TReadonlyFromMappedResult /** `[Json]` Creates a Readonly property */ - public Readonly(schema: T): TReadonlyWithFlag + public Readonly(type: Type): TReadonlyWithFlag /** `[Json]` Creates a Readonly property */ - public Readonly(schema: TSchema, enable?: boolean): any { - return Readonly(schema, enable ?? true) + public Readonly(type: TSchema, enable?: boolean): any { + return Readonly(type, enable ?? true) } /** `[Json]` Creates a Optional property */ - public Optional(schema: T, enable: F): TOptionalFromMappedResult + public Optional(type: Type, enable: Flag): TOptionalFromMappedResult /** `[Json]` Creates a Optional property */ - public Optional(schema: T, enable: F): TOptionalWithFlag + public Optional(type: Type, enable: Flag): TOptionalWithFlag /** `[Json]` Creates a Optional property */ - public Optional(schema: T): TOptionalFromMappedResult + public Optional(type: Type): TOptionalFromMappedResult /** `[Json]` Creates a Optional property */ - public Optional(schema: T): TOptionalWithFlag + public Optional(type: Type): TOptionalWithFlag /** `[Json]` Creates a Optional property */ - public Optional(schema: TSchema, enable?: boolean): any { - return Optional(schema, enable ?? true) + public Optional(type: TSchema, enable?: boolean): any { + return Optional(type, enable ?? true) } // ------------------------------------------------------------------------ // Types @@ -110,8 +110,8 @@ export class JsonTypeBuilder { return Any(options) } /** `[Json]` Creates an Array type */ - public Array(schema: T, options?: ArrayOptions): TArray { - return Array(schema, options) + public Array(items: Type, options?: ArrayOptions): TArray { + return Array(items, options) } /** `[Json]` Creates a Boolean type */ public Boolean(options?: SchemaOptions): TBoolean { @@ -164,36 +164,36 @@ export class JsonTypeBuilder { return Extract(type, union, options) } /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(T: T, K: K, options?: SchemaOptions): TIndexFromMappedResult + public Index(type: Type, key: readonly [...PropertyKeys], options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(T: T, K: K, options?: SchemaOptions): TIndexFromMappedKey + public Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ - public Index>(T: T, K: K, options?: SchemaOptions): TIndex + public Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(T: T, K: readonly [...K], options?: SchemaOptions): TIndex + public Index(type: Type, key: Key, options?: SchemaOptions): TIndex /** `[Json]` Returns an Indexed property type for the given keys */ - public Index(schema: TSchema, unresolved: any, options?: SchemaOptions): any { - return Index(schema, unresolved, options) + public Index(type: TSchema, key: any, options?: SchemaOptions): any { + return Index(type, key, options) } /** `[Json]` Creates an Integer type */ public Integer(options?: IntegerOptions): TInteger { return Integer(options) } /** `[Json]` Creates an Intersect type */ - public Intersect(T: [...T], options?: IntersectOptions): Intersect { - return Intersect(T, options) + public Intersect(types: [...Types], options?: IntersectOptions): Intersect { + return Intersect(types, options) } /** `[Json]` Creates a KeyOf type */ - public KeyOf(schema: Type, options?: SchemaOptions): TKeyOf { - return KeyOf(schema, options) as never + public KeyOf(type: Type, options?: SchemaOptions): TKeyOf { + return KeyOf(type, options) as never } /** `[Json]` Creates a Literal type */ - public Literal(value: T, options?: SchemaOptions): TLiteral { - return Literal(value, options) + public Literal(literalValue: LiteralValue, options?: SchemaOptions): TLiteral { + return Literal(literalValue, options) } /** `[Json]` Intrinsic function to Lowercase LiteralString types */ - public Lowercase(schema: T, options?: SchemaOptions): TLowercase { - return Lowercase(schema, options) + public Lowercase(type: Type, options?: SchemaOptions): TLowercase { + return Lowercase(type, options) } /** `[Json]` Creates a Mapped object type */ public Mapped, F extends TMappedFunction = TMappedFunction, R extends TMapped = TMapped>(key: K, map: F, options?: ObjectOptions): R @@ -212,8 +212,8 @@ export class JsonTypeBuilder { return Never(options) } /** `[Json]` Creates a Not type */ - public Not(schema: T, options?: SchemaOptions): TNot { - return Not(schema, options) + public Not(type: T, options?: SchemaOptions): TNot { + return Not(type, options) } /** `[Json]` Creates a Null type */ public Null(options?: SchemaOptions): TNull { @@ -236,7 +236,7 @@ export class JsonTypeBuilder { return Omit(schema, selector, options) } /** `[Json]` Constructs a type where all properties are optional */ - public Partial(mappedResult: MappedResult, options?: SchemaOptions): TPartialFromMappedResult + public Partial(type: MappedResult, options?: SchemaOptions): TPartialFromMappedResult /** `[Json]` Constructs a type where all properties are optional */ public Partial(type: Type, options?: SchemaOptions): TPartial /** `[Json]` Constructs a type where all properties are optional */ @@ -252,8 +252,8 @@ export class JsonTypeBuilder { return Pick(type, key, options) } /** `[Json]` Creates a Record type */ - public Record(key: K, schema: T, options?: ObjectOptions): TRecordOrObject { - return Record(key, schema, options) + public Record(key: Key, value: Value, options?: ObjectOptions): TRecordOrObject { + return Record(key, value, options) } /** `[Json]` Creates a Recursive type */ public Recursive(callback: (thisType: TThis) => T, options?: SchemaOptions): TRecursive { @@ -264,7 +264,7 @@ export class JsonTypeBuilder { return Ref($ref, options) } /** `[Json]` Constructs a type where all properties are required */ - public Required(mappedResult: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult + public Required(type: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult /** `[Json]` Constructs a type where all properties are required */ public Required(type: Type, options?: SchemaOptions): TRequired /** `[Json]` Constructs a type where all properties are required */ @@ -272,36 +272,36 @@ export class JsonTypeBuilder { return Required(type, options) } /** `[Json]` Extracts interior Rest elements from Tuple, Intersect and Union types */ - public Rest(schema: T): TRest { - return Rest(schema) + public Rest(type: Type): TRest { + return Rest(type) } /** `[Json]` Creates a String type */ public String(options?: StringOptions): TString { return String(options) } /** `[Json]` Creates a TemplateLiteral type from template dsl string */ - public TemplateLiteral(syntax: T, options?: SchemaOptions): TTemplateLiteralSyntax + public TemplateLiteral(syntax: Syntax, options?: SchemaOptions): TTemplateLiteralSyntax /** `[Json]` Creates a TemplateLiteral type */ - public TemplateLiteral(kinds: [...T], options?: SchemaOptions): TTemplateLiteral + public TemplateLiteral(kinds: [...Kinds], options?: SchemaOptions): TTemplateLiteral /** `[Json]` Creates a TemplateLiteral type */ public TemplateLiteral(unresolved: TTemplateLiteralKind[] | string, options?: SchemaOptions) { return TemplateLiteral(unresolved as any, options) } /** `[Json]` Creates a Transform type */ - public Transform(schema: I): TransformDecodeBuilder { - return Transform(schema) + public Transform(type: Type): TransformDecodeBuilder { + return Transform(type) } /** `[Json]` Creates a Tuple type */ - public Tuple(items: [...T], options?: SchemaOptions): TTuple { - return Tuple(items, options) + public Tuple(types: [...Types], options?: SchemaOptions): TTuple { + return Tuple(types, options) } /** `[Json]` Intrinsic function to Uncapitalize LiteralString types */ - public Uncapitalize(schema: T, options?: SchemaOptions): TUncapitalize { - return Uncapitalize(schema, options) + public Uncapitalize(type: Type, options?: SchemaOptions): TUncapitalize { + return Uncapitalize(type, options) } /** `[Json]` Creates a Union type */ - public Union(schemas: [...T], options?: SchemaOptions): Union { - return Union(schemas, options) + public Union(types: [...Types], options?: SchemaOptions): Union { + return Union(types, options) } /** `[Json]` Creates an Unknown type */ public Unknown(options?: SchemaOptions): TUnknown { diff --git a/src/type/union/union-evaluated.ts b/src/type/union/union-evaluated.ts index 9e4004a20..8ba1eb21b 100644 --- a/src/type/union/union-evaluated.ts +++ b/src/type/union/union-evaluated.ts @@ -44,43 +44,43 @@ import { IsOptional } from '../guard/kind' // IsUnionOptional // ------------------------------------------------------------------ // prettier-ignore -type TIsUnionOptional = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] ? - L extends TOptional +type TIsUnionOptional = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] ? + Left extends TOptional ? true - : TIsUnionOptional + : TIsUnionOptional : false ) // prettier-ignore -function IsUnionOptional(T: T): TIsUnionOptional { - return T.some(L => IsOptional(L)) as never +function IsUnionOptional(types: Types): TIsUnionOptional { + return types.some(type => IsOptional(type)) as never } // ------------------------------------------------------------------ // RemoveOptionalFromRest // ------------------------------------------------------------------ // prettier-ignore -type TRemoveOptionalFromRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? L extends TOptional - ? TRemoveOptionalFromRest]> - : TRemoveOptionalFromRest - : Acc +type TRemoveOptionalFromRest = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TOptional + ? TRemoveOptionalFromRest]> + : TRemoveOptionalFromRest + : Result ) // prettier-ignore -function RemoveOptionalFromRest(T: T): TRemoveOptionalFromRest { - return T.map(L => IsOptional(L) ? RemoveOptionalFromType(L) : L) as never +function RemoveOptionalFromRest(types: Types): TRemoveOptionalFromRest { + return types.map(left => IsOptional(left) ? RemoveOptionalFromType(left) : left) as never } // ------------------------------------------------------------------ // RemoveOptionalFromType // ------------------------------------------------------------------ // prettier-ignore -type TRemoveOptionalFromType = ( - T extends TReadonly ? TReadonly> : - T extends TOptional ? TRemoveOptionalFromType : - T +type TRemoveOptionalFromType = ( + Type extends TReadonly ? TReadonly> : + Type extends TOptional ? TRemoveOptionalFromType : + Type ) // prettier-ignore -function RemoveOptionalFromType(T: T): TRemoveOptionalFromType { +function RemoveOptionalFromType(T: Type): TRemoveOptionalFromType { return ( Discard(T, [OptionalKind]) ) as never @@ -89,34 +89,38 @@ function RemoveOptionalFromType(T: T): TRemoveOptionalFromTyp // ResolveUnion // ------------------------------------------------------------------ // prettier-ignore -type TResolveUnion> = ( - TIsUnionOptional extends true - ? TOptional> - : TUnion +type TResolveUnion, + IsOptional extends boolean = TIsUnionOptional +> = ( + IsOptional extends true + ? TOptional> + : TUnion ) // prettier-ignore -function ResolveUnion(T: T, options?: SchemaOptions): TResolveUnion { +function ResolveUnion(types: Types, options?: SchemaOptions): TResolveUnion { + const isOptional = IsUnionOptional(types) return ( - IsUnionOptional(T) - ? Optional(UnionCreate(RemoveOptionalFromRest(T) as TSchema[], options)) - : UnionCreate(RemoveOptionalFromRest(T) as TSchema[], options) + isOptional + ? Optional(UnionCreate(RemoveOptionalFromRest(types) as TSchema[], options)) + : UnionCreate(RemoveOptionalFromRest(types) as TSchema[], options) ) as never } // ------------------------------------------------------------------ // Union // ------------------------------------------------------------------ // prettier-ignore -export type TUnionEvaluated = ( - T extends [] ? TNever : - T extends [TSchema] ? T[0] : - TResolveUnion +export type TUnionEvaluated = ( + Types extends [TSchema] ? Types[0] : + Types extends [] ? TNever : + TResolveUnion ) /** `[Json]` Creates an evaluated Union type */ -export function UnionEvaluated>(T: [...T], options?: SchemaOptions): R { +export function UnionEvaluated>(T: [...Types], options?: SchemaOptions): Result { // prettier-ignore return ( - T.length === 0 ? Never(options) : T.length === 1 ? CreateType(T[0], options) : + T.length === 0 ? Never(options) : ResolveUnion(T, options) ) as never } diff --git a/src/type/union/union.ts b/src/type/union/union.ts index a057141c8..bacffbd19 100644 --- a/src/type/union/union.ts +++ b/src/type/union/union.ts @@ -39,11 +39,11 @@ export type Union = ( TUnion ) /** `[Json]` Creates a Union type */ -export function Union(T: [...T], options?: SchemaOptions): Union { +export function Union(types: [...Types], options?: SchemaOptions): Union { // prettier-ignore return ( - T.length === 0 ? Never(options) : - T.length === 1 ? CreateType(T[0], options) : - UnionCreate(T, options) - ) as Union + types.length === 0 ? Never(options) : + types.length === 1 ? CreateType(types[0], options) : + UnionCreate(types, options) + ) as Union }