From cb8ec1ef176ae211ce6ae5c8fffe3df137481ca5 Mon Sep 17 00:00:00 2001 From: sinclair Date: Thu, 14 Nov 2024 16:58:20 +0900 Subject: [PATCH 1/5] Implement Computed Deref Types for Import --- package-lock.json | 4 +- package.json | 2 +- readme.md | 41 +- src/compiler/compiler.ts | 2 +- src/errors/errors.ts | 2 +- src/syntax/runtime.ts | 5 +- src/syntax/static.ts | 10 +- src/type/array/array.ts | 2 +- src/type/awaited/awaited.ts | 94 ++-- src/type/computed/computed.ts | 44 ++ src/type/computed/index.ts | 29 ++ src/type/guard/kind.ts | 17 +- src/type/guard/type.ts | 12 +- src/type/indexed/indexed-from-mapped-key.ts | 63 ++- .../indexed/indexed-from-mapped-result.ts | 21 +- src/type/indexed/indexed-property-keys.ts | 60 +-- src/type/indexed/indexed.ts | 266 +++++++----- src/type/intersect/intersect-evaluated.ts | 74 ++-- src/type/intersect/intersect.ts | 18 +- src/type/keyof/keyof-from-mapped-result.ts | 46 +- src/type/keyof/keyof-property-keys.ts | 94 ++-- src/type/keyof/keyof.ts | 86 ++-- src/type/module/compute.ts | 402 ++++++++++++++++++ src/type/module/infer.ts | 162 +++++++ src/type/module/module.ts | 147 +------ src/type/not/not.ts | 4 +- src/type/omit/omit-from-mapped-key.ts | 73 ++-- src/type/omit/omit-from-mapped-result.ts | 52 +-- src/type/omit/omit.ts | 163 ++++--- src/type/partial/partial.ts | 100 +++-- src/type/pick/pick-from-mapped-key.ts | 71 ++-- src/type/pick/pick-from-mapped-result.ts | 52 +-- src/type/pick/pick.ts | 162 ++++--- src/type/record/record.ts | 51 ++- src/type/required/required.ts | 108 +++-- src/type/tuple/tuple.ts | 8 +- src/type/type/javascript.ts | 26 +- src/type/type/json.ts | 146 +++---- src/type/union/union-evaluated.ts | 70 +-- src/type/union/union.ts | 10 +- src/value/cast/cast.ts | 2 +- src/value/check/check.ts | 6 +- src/value/clean/clean.ts | 2 +- src/value/convert/convert.ts | 2 +- src/value/create/create.ts | 2 +- src/value/default/default.ts | 2 +- src/value/transform/decode.ts | 6 +- src/value/transform/encode.ts | 6 +- src/value/transform/has.ts | 4 +- test/runtime/type/guard/kind/import.ts | 150 ++++++- test/runtime/type/guard/type/import.ts | 148 ++++++- test/static/pick.ts | 2 +- 52 files changed, 2070 insertions(+), 1061 deletions(-) create mode 100644 src/type/computed/computed.ts create mode 100644 src/type/computed/index.ts create mode 100644 src/type/module/compute.ts create mode 100644 src/type/module/infer.ts diff --git a/package-lock.json b/package-lock.json index fbacace2e..3dab50690 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@sinclair/typebox", - "version": "0.34.0", + "version": "0.34.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@sinclair/typebox", - "version": "0.34.0", + "version": "0.34.1", "license": "MIT", "devDependencies": { "@arethetypeswrong/cli": "^0.13.2", diff --git a/package.json b/package.json index 44b16b8e3..5c9bf671d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.34.0", + "version": "0.34.1", "description": "Json Schema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", diff --git a/readme.md b/readme.md index 3adeae926..10b29574c 100644 --- a/readme.md +++ b/readme.md @@ -1074,22 +1074,25 @@ const T = Type.Object({ // const T: TObject<{ ### Module -Syntax Types support Module parsing, which is useful for processing multiple TypeScript types. Module parsing supports type alias and interface definitions. Generics are currently unsupported as of 0.34.0. +Syntax Types also support Module parsing. This can provide a more terse syntax for creating Module definitions, but comes with an inference performance cost. Module parsing supports interface and type alias definitions. Generics types are currently unsupported. Consider the following which defines a explicit Module on the left, and the parsed Module on the right. ```typescript -const Foo = Parse(`module Foo { - - export type A = string - - export type B = number - - export type C = A | B - -}`) - -const C = Foo.Import('C') // const C: TImport<{ - // ... - // }, 'C'> +const Module = Type.Module({ // const Module = Parse(`module { + // + User: Type.Object({ // export interface User { + id: Type.String(), // id: string + name: Type.String(), // name: string + email: Type.String(), // email: string + }), // } + // + PartialUser: Type.Intersect([ // export type PartialUser = ( + Type.Pick(Type.Ref('User'), ['id']), // Pick & + Type.Partial( // Partial> + Type.Omit(Type.Ref('User'), ['id']) // ) + ), // + ]) // + // +}) // }`) ``` @@ -1883,12 +1886,12 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m ┌──────────────────────┬────────────┬────────────┬─────────────┐ │ (index) │ Compiled │ Minified │ Compression │ ├──────────────────────┼────────────┼────────────┼─────────────┤ -│ typebox/compiler │ '121.7 kb' │ ' 53.4 kb' │ '2.28 x' │ -│ typebox/errors │ ' 75.3 kb' │ ' 33.4 kb' │ '2.25 x' │ -│ typebox/syntax │ '120.1 kb' │ ' 50.5 kb' │ '2.38 x' │ +│ typebox/compiler │ '122.4 kb' │ ' 53.4 kb' │ '2.29 x' │ +│ typebox/errors │ ' 67.6 kb' │ ' 29.6 kb' │ '2.28 x' │ +│ typebox/syntax │ '132.9 kb' │ ' 54.2 kb' │ '2.45 x' │ │ typebox/system │ ' 7.4 kb' │ ' 3.2 kb' │ '2.33 x' │ -│ typebox/value │ '160.3 kb' │ ' 67.4 kb' │ '2.38 x' │ -│ typebox │ ' 96.2 kb' │ ' 40.2 kb' │ '2.39 x' │ +│ typebox/value │ '150.1 kb' │ ' 62.2 kb' │ '2.41 x' │ +│ typebox │ '106.8 kb' │ ' 43.2 kb' │ '2.47 x' │ └──────────────────────┴────────────┴────────────┴─────────────┘ ``` diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 6e438702b..01ab4dcf6 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -291,7 +291,7 @@ export namespace TypeCompiler { } function* FromImport(schema: TImport, references: TSchema[], value: string): IterableIterator { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema yield* Visit(target, [...references, ...definitions], value) } function* FromInteger(schema: TInteger, references: TSchema[], value: string): IterableIterator { diff --git a/src/errors/errors.ts b/src/errors/errors.ts index 9bb1f6cd1..b7ac37f4c 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -305,7 +305,7 @@ function* FromFunction(schema: TFunction, references: TSchema[], path: string, v } function* FromImport(schema: TImport, references: TSchema[], path: string, value: any): IterableIterator { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema yield* Visit(target, [...references, ...definitions], path, value) } function* FromInteger(schema: TInteger, references: TSchema[], path: string, value: any): IterableIterator { 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/syntax/static.ts b/src/syntax/static.ts index 0b30b8ead..ddd48ea76 100644 --- a/src/syntax/static.ts +++ b/src/syntax/static.ts @@ -776,7 +776,7 @@ type Partial = Static.Tuple<[ // prettier-ignore interface RequiredMapping extends Static.IMapping { output: this['input'] extends ['Required', LAngle, infer Type extends Types.TSchema, RAngle] - ? Types.TPartial + ? Types.TRequired : never } // prettier-ignore @@ -788,8 +788,8 @@ type Required = Static.Tuple<[ // ------------------------------------------------------------------ // prettier-ignore interface PickMapping extends Static.IMapping { - output: this['input'] extends ['Pick', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle] - ? Types.TPick> + output: this['input'] extends ['Pick', LAngle, infer Type extends Types.TSchema, Comma, infer Key extends Types.TSchema, RAngle] + ? Types.TPick : never } // prettier-ignore @@ -801,8 +801,8 @@ type Pick = Static.Tuple<[ // ------------------------------------------------------------------ // prettier-ignore interface OmitMapping extends Static.IMapping { - output: this['input'] extends ['Omit', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle] - ? Types.TOmit> + output: this['input'] extends ['Omit', LAngle, infer Type extends Types.TSchema, Comma, infer Key extends Types.TSchema, RAngle] + ? Types.TOmit : never } // prettier-ignore 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/awaited/awaited.ts b/src/type/awaited/awaited.ts index e129b6a52..1a849f14e 100644 --- a/src/type/awaited/awaited.ts +++ b/src/type/awaited/awaited.ts @@ -26,76 +26,96 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ +import { CreateType } from '../create/type' +import { Ensure } from '../helpers/index' import type { TSchema, SchemaOptions } from '../schema/index' +import { Computed, type TComputed } from '../computed/index' import { Intersect, type TIntersect } from '../intersect/index' import { Union, type TUnion } from '../union/index' import { type TPromise } from '../promise/index' -import { CreateType } from '../create/type' +import { Ref, type TRef } from '../ref/index' // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsIntersect, IsUnion, IsPromise } from '../guard/kind' -// ------------------------------------------------------------------ -// FromRest -// ------------------------------------------------------------------ +import { IsIntersect, IsUnion, IsPromise, IsRef, IsComputed } from '../guard/kind' + +// ---------------------------------------------------------------- +// FromComputed +// ---------------------------------------------------------------- // prettier-ignore -type TFromRest = - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest]> - : Acc +type TFromComputed = Ensure<( + TComputed<'Awaited', [TComputed]> +)> +// prettier-ignore +function FromComputed(target: Target, parameters: Parameters): TFromComputed { + return Computed('Awaited', [Computed(target, parameters)]) as never +} +// ---------------------------------------------------------------- +// Ref +// ---------------------------------------------------------------- +type TFromRef = Ensure]>> // prettier-ignore -function FromRest(T: [...T]) : TFromRest { - return T.map(L => AwaitedResolve(L)) as never +function FromRef($ref: Ref): TFromRef { + return Computed('Awaited', [Ref($ref)]) as never } // ---------------------------------------------------------------- // FromIntersect // ---------------------------------------------------------------- // prettier-ignore -type TFromIntersect = TIntersect> +type TFromIntersect = ( + TIntersect> +) // prettier-ignore -function FromIntersect(T: [...T]): TFromIntersect { - return Intersect(FromRest(T) as TSchema[]) as never +function FromIntersect(types: [...Types]): TFromIntersect { + return Intersect(FromRest(types) as TSchema[]) as never } // ---------------------------------------------------------------- // FromUnion // ---------------------------------------------------------------- // prettier-ignore -type TFromUnion = TUnion> +type TFromUnion = TUnion> // prettier-ignore -function FromUnion(T: [...T]): TFromUnion { - return Union(FromRest(T) as TSchema[]) as never +function FromUnion(types: [...Types]): TFromUnion { + return Union(FromRest(types) as TSchema[]) as never } // ---------------------------------------------------------------- // Promise // ---------------------------------------------------------------- -type TFromPromise = TAwaited +type TFromPromise = TAwaited // prettier-ignore -function FromPromise(T: T): TFromPromise { - return AwaitedResolve(T) as never +function FromPromise(type: Type): TFromPromise { + return Awaited(type) as never } -// ---------------------------------------------------------------- -// AwaitedResolve -// ---------------------------------------------------------------- +// ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ // prettier-ignore -function AwaitedResolve(T: T): TAwaited { - return ( - IsIntersect(T) ? FromIntersect(T.allOf) : - IsUnion(T) ? FromUnion(T.anyOf) : - IsPromise(T) ? FromPromise(T.item) : - T - ) as never +type TFromRest = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? TFromRest]> + : Result +) +// prettier-ignore +function FromRest(types: [...Types]) : TFromRest { + return types.map(type => Awaited(type)) as never } // ------------------------------------------------------------------ // TAwaited // ------------------------------------------------------------------ // prettier-ignore -export type TAwaited = - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TPromise ? TAwaited : - T +export type TAwaited = ( + Type extends TComputed ? TFromComputed : + Type extends TRef ? TFromRef : + Type extends TIntersect ? TIntersect> : + Type extends TUnion ? TUnion> : + Type extends TPromise ? TAwaited : + Type +) /** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */ -export function Awaited(T: T, options?: SchemaOptions): TAwaited { - return CreateType(AwaitedResolve(T), options) as never +export function Awaited(type: T, options?: SchemaOptions): TAwaited { + return CreateType( + IsComputed(type) ? FromComputed(type.target, type.parameters) : IsIntersect(type) ? FromIntersect(type.allOf) : IsUnion(type) ? FromUnion(type.anyOf) : IsPromise(type) ? FromPromise(type.item) : IsRef(type) ? FromRef(type.$ref) : type, + options, + ) as never } diff --git a/src/type/computed/computed.ts b/src/type/computed/computed.ts new file mode 100644 index 000000000..2524dc152 --- /dev/null +++ b/src/type/computed/computed.ts @@ -0,0 +1,44 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema, SchemaOptions } from '../schema/index' +import { CreateType } from '../create/index' +import { Kind } from '../symbols/symbols' + +// ------------------------------------------------------------------ +// Computed +// ------------------------------------------------------------------ +export interface TComputed extends TSchema { + [Kind]: 'Computed' + target: Target + parameters: Parameters +} +/** `[Internal]` Creates a deferred computed type. This type is used exclusively in modules to defer resolution of computable types that contain interior references */ +export function Computed(target: Target, parameters: [...Parameters], options?: SchemaOptions): TComputed { + return CreateType({ [Kind]: 'Computed', target, parameters }, options) as never +} diff --git a/src/type/computed/index.ts b/src/type/computed/index.ts new file mode 100644 index 000000000..4d20b1f87 --- /dev/null +++ b/src/type/computed/index.ts @@ -0,0 +1,29 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +export * from './computed' diff --git a/src/type/guard/kind.ts b/src/type/guard/kind.ts index 2e61a1df9..95e14fc2f 100644 --- a/src/type/guard/kind.ts +++ b/src/type/guard/kind.ts @@ -29,9 +29,10 @@ THE SOFTWARE. import * as ValueGuard from './value' import { Kind, Hint, TransformKind, ReadonlyKind, OptionalKind } from '../symbols/index' import { TransformOptions } from '../transform/index' -import { TTemplateLiteral } from '../template-literal/index' -import { TArray } from '../array/index' -import { TBoolean } from '../boolean/index' +import type { TTemplateLiteral } from '../template-literal/index' +import type { TArray } from '../array/index' +import type { TBoolean } from '../boolean/index' +import type { TComputed } from '../computed/index' import type { TRecord } from '../record/index' import type { TString } from '../string/index' import type { TUnion } from '../union/index' @@ -44,7 +45,7 @@ import type { TImport } from '../module/index' import type { TInteger } from '../integer/index' import type { TIntersect } from '../intersect/index' import type { TIterator } from '../iterator/index' -import type { TLiteral } from '../literal/index' +import type { TLiteral, TLiteralValue } from '../literal/index' import type { TMappedKey, TMappedResult } from '../mapped/index' import type { TNever } from '../never/index' import type { TNot } from '../not/index' @@ -95,6 +96,10 @@ export function IsBigInt(value: unknown): value is TBigInt { export function IsBoolean(value: unknown): value is TBoolean { return IsKindOf(value, 'Boolean') } +/** `[Kind-Only]` Returns true if the given value is TComputed */ +export function IsComputed(value: unknown): value is TComputed { + return IsKindOf(value, 'Computed') +} /** `[Kind-Only]` Returns true if the given value is TConstructor */ export function IsConstructor(value: unknown): value is TConstructor { return IsKindOf(value, 'Constructor') @@ -143,6 +148,10 @@ export function IsLiteralNumber(value: unknown): value is TLiteral { export function IsLiteralBoolean(value: unknown): value is TLiteral { return IsLiteral(value) && ValueGuard.IsBoolean(value.const) } +/** `[Kind-Only]` Returns true if the given value is TLiteralValue */ +export function IsLiteralValue(value: unknown): value is TLiteralValue { + return ValueGuard.IsBoolean(value) || ValueGuard.IsNumber(value) || ValueGuard.IsString(value) +} /** `[Kind-Only]` Returns true if the given value is TLiteral */ export function IsLiteral(value: unknown): value is TLiteral { return IsKindOf(value, 'Literal') diff --git a/src/type/guard/type.ts b/src/type/guard/type.ts index ed8eb54fe..b4564bed2 100644 --- a/src/type/guard/type.ts +++ b/src/type/guard/type.ts @@ -30,9 +30,10 @@ import * as ValueGuard from './value' import { Kind, Hint, TransformKind, ReadonlyKind, OptionalKind } from '../symbols/index' import { TypeBoxError } from '../error/index' import { TransformOptions } from '../transform/index' -import { TTemplateLiteral } from '../template-literal/index' -import { TArray } from '../array/index' -import { TBoolean } from '../boolean/index' +import type { TTemplateLiteral } from '../template-literal/index' +import type { TArray } from '../array/index' +import type { TBoolean } from '../boolean/index' +import type { TComputed } from '../computed/index' import type { TRecord } from '../record/index' import type { TString } from '../string/index' import type { TUnion } from '../union/index' @@ -76,6 +77,7 @@ const KnownTypes = [ 'AsyncIterator', 'BigInt', 'Boolean', + 'Computed', 'Constructor', 'Date', 'Enum', @@ -217,6 +219,10 @@ export function IsBoolean(value: unknown): value is TBoolean { IsOptionalString(value.$id) ) } +/** Returns true if the given value is TComputed */ +export function IsComputed(value: unknown): value is TComputed { + return IsKindOf(value, 'Computed') && IsString(value.target) && ValueGuard.IsArray(value.parameters) && value.parameters.every((schema) => IsSchema(schema)) +} /** Returns true if the given value is TConstructor */ export function IsConstructor(value: unknown): value is TConstructor { // prettier-ignore 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..5598b034c 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,83 @@ 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 (do not export this type) +type TResolvePropertyKeys = Key extends TSchema ? TIndexPropertyKeys : Key +// prettier-ignore (do not export this type) +type TResolveTypeKey = Key extends PropertyKey[] ? TUnionFromPropertyKeys : Key // prettier-ignore -export type TIndex = ( - FromSchema +export type TIndex = ( + Key extends TMappedResult ? TIndexFromMappedResult : + Key extends TMappedKey ? TIndexFromMappedKey : + [IsTypeRef, IsKeyRef] extends [true, true] ? TComputed<'Index', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [false, true] ? TComputed<'Index', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [true, false] ? TComputed<'Index', [Type, TResolveTypeKey]> : + 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/keyof/keyof-from-mapped-result.ts b/src/type/keyof/keyof-from-mapped-result.ts index 9991b7c15..0be659752 100644 --- a/src/type/keyof/keyof-from-mapped-result.ts +++ b/src/type/keyof/keyof-from-mapped-result.ts @@ -30,55 +30,47 @@ import type { SchemaOptions } from '../schema/index' import type { Ensure, Evaluate } from '../helpers/index' import type { TProperties } from '../object/index' import { MappedResult, type TMappedResult } from '../mapped/index' -import { KeyOf, type TKeyOf } from './keyof' +import { KeyOf, type TKeyOfFromType } from './keyof' import { Clone } from '../clone/value' // ------------------------------------------------------------------ // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties< - K extends TProperties -> = ( - { [K2 in keyof K]: TKeyOf } +type TFromProperties = ( + { [K2 in keyof Properties]: TKeyOfFromType } ) // prettier-ignore -function FromProperties< - K extends TProperties ->(K: K, options?: SchemaOptions): TFromProperties { - const Acc = {} as TProperties - for(const K2 of globalThis.Object.getOwnPropertyNames(K)) Acc[K2] = KeyOf(K[K2], Clone(options)) - return Acc as never +function FromProperties(properties: Properties, options?: SchemaOptions): TFromProperties { + const result = {} as TProperties + for(const K2 of globalThis.Object.getOwnPropertyNames(properties)) result[K2] = KeyOf(properties[K2], Clone(options)) + return result as never } // ------------------------------------------------------------------ // FromMappedResult // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedResult< - R extends TMappedResult -> = ( - Evaluate> +type TFromMappedResult = ( + Evaluate> ) // prettier-ignore -function FromMappedResult< - R extends TMappedResult ->(R: R, options?: SchemaOptions): TFromMappedResult { - return FromProperties(R.properties, options) as never +function FromMappedResult(mappedResult: MappedResult, options?: SchemaOptions): TFromMappedResult { + return FromProperties(mappedResult.properties, options) as never } // ------------------------------------------------------------------ // KeyOfFromMappedResult // ------------------------------------------------------------------ // prettier-ignore export type TKeyOfFromMappedResult< - R extends TMappedResult, - P extends TProperties = TFromMappedResult + MappedResult extends TMappedResult, + Properties extends TProperties = TFromMappedResult > = ( - Ensure> + Ensure> ) // prettier-ignore export function KeyOfFromMappedResult< - R extends TMappedResult, - P extends TProperties = TFromMappedResult ->(R: R, options?: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(R, options) - return MappedResult(P) as never + MappedResult extends TMappedResult, + Properties extends TProperties = TFromMappedResult +>(mappedResult: MappedResult, options?: SchemaOptions): TMappedResult { + const properties = FromMappedResult(mappedResult, options) + return MappedResult(properties) as never } diff --git a/src/type/keyof/keyof-property-keys.ts b/src/type/keyof/keyof-property-keys.ts index 28f945bb1..25cfd2df3 100644 --- a/src/type/keyof/keyof-property-keys.ts +++ b/src/type/keyof/keyof-property-keys.ts @@ -44,58 +44,56 @@ import { IsIntersect, IsUnion, IsTuple, IsArray, IsObject, IsRecord } from '../g // FromRest // ------------------------------------------------------------------ // prettier-ignore -type TFromRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest]> - : Acc +type TFromRest = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromRest]> + : Result ) // prettier-ignore -function FromRest(T: [...T]): TFromRest { - const Acc = [] as PropertyKey[][] - for(const L of T) Acc.push(KeyOfPropertyKeys(L)) - return Acc as never +function FromRest(types: [...Types]): TFromRest { + const result = [] as PropertyKey[][] + for(const L of types) result.push(KeyOfPropertyKeys(L)) + return result as never } // ------------------------------------------------------------------ // FromIntersect // ------------------------------------------------------------------ // prettier-ignore -type TFromIntersect< - T extends TSchema[], - C extends PropertyKey[][] = TFromRest, - R extends PropertyKey[] = TSetUnionMany -> = R +type TFromIntersect, + PropertyKeys extends PropertyKey[] = TSetUnionMany +> = PropertyKeys // prettier-ignore -function FromIntersect(T: [...T]): TFromIntersect { - const C = FromRest(T) as PropertyKey[][] - const R = SetUnionMany(C) - return R as never +function FromIntersect(types: [...Types]): TFromIntersect { + const propertyKeysArray = FromRest(types) as PropertyKey[][] + const propertyKeys = SetUnionMany(propertyKeysArray) + return propertyKeys as never } // ------------------------------------------------------------------ // FromUnion // ------------------------------------------------------------------ // prettier-ignore -type TFromUnion< - T extends TSchema[], - C extends PropertyKey[][] = TFromRest, - R extends PropertyKey[] = TSetIntersectMany -> = R +type TFromUnion, + PropertyKeys extends PropertyKey[] = TSetIntersectMany +> = PropertyKeys // prettier-ignore -function FromUnion(T: [...T]): TFromUnion { - const C = FromRest(T) as PropertyKey[][] - const R = SetIntersectMany(C) - return R as never +function FromUnion(types: [...Types]): TFromUnion { + const propertyKeysArray = FromRest(types) as PropertyKey[][] + const propertyKeys = SetIntersectMany(propertyKeysArray) + return propertyKeys as never } // ------------------------------------------------------------------ // FromTuple // ------------------------------------------------------------------ // prettier-ignore -type TFromTuple = - T extends [infer _ extends TSchema, ...infer R extends TSchema[]] - ? TFromTuple, [...Acc, I]> +type TFromTuple = + Types extends [infer _ extends TSchema, ...infer R extends TSchema[]] + ? TFromTuple, [...Acc, Indexer]> : Acc // prettier-ignore -function FromTuple(T: [...T]): TFromTuple { - return T.map((_, I) => I.toString()) as never +function FromTuple(types: [...Types]): TFromTuple { + return types.map((_, indexer) => indexer.toString()) as never } // ------------------------------------------------------------------ // FromArray @@ -114,11 +112,11 @@ function FromArray<_ extends TSchema>(_: _): TFromArray<_> { // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties = ( - UnionToTuple +type TFromProperties = ( + UnionToTuple ) // prettier-ignore -function FromProperties(T: T): TFromProperties { +function FromProperties(T: Properties): TFromProperties { return ( globalThis.Object.getOwnPropertyNames(T) ) as never @@ -140,25 +138,25 @@ function FromPatternProperties(patternProperties: Record): // KeyOfPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -export type TKeyOfPropertyKeys = ( - T extends TRecursive ? TKeyOfPropertyKeys : - T extends TIntersect ? TFromIntersect : - T extends TUnion ? TFromUnion : - T extends TTuple ? TFromTuple : - T extends TArray ? TFromArray : - T extends TObject ? TFromProperties : +export type TKeyOfPropertyKeys = ( + Type extends TRecursive ? TKeyOfPropertyKeys : + Type extends TIntersect ? TFromIntersect : + Type extends TUnion ? TFromUnion : + Type extends TTuple ? TFromTuple : + Type extends TArray ? TFromArray : + Type extends TObject ? TFromProperties : [] ) /** Returns a tuple of PropertyKeys derived from the given TSchema. */ // prettier-ignore -export function KeyOfPropertyKeys(T: T): TKeyOfPropertyKeys { +export function KeyOfPropertyKeys(type: Type): TKeyOfPropertyKeys { return ( - IsIntersect(T) ? FromIntersect(T.allOf) : - IsUnion(T) ? FromUnion(T.anyOf) : - IsTuple(T) ? FromTuple(T.items ?? []) : - IsArray(T) ? FromArray(T.items) : - IsObject(T) ? FromProperties(T.properties) : - IsRecord(T) ? FromPatternProperties(T.patternProperties) : + IsIntersect(type) ? FromIntersect(type.allOf) : + IsUnion(type) ? FromUnion(type.anyOf) : + IsTuple(type) ? FromTuple(type.items ?? []) : + IsArray(type) ? FromArray(type.items) : + IsObject(type) ? FromProperties(type.properties) : + IsRecord(type) ? FromPatternProperties(type.patternProperties) : [] ) as never } diff --git a/src/type/keyof/keyof.ts b/src/type/keyof/keyof.ts index 2e4c42df6..fbd20df62 100644 --- a/src/type/keyof/keyof.ts +++ b/src/type/keyof/keyof.ts @@ -33,6 +33,8 @@ import type { TMappedResult } from '../mapped/index' import type { SchemaOptions } from '../schema/index' import { Literal, type TLiteral, type TLiteralValue } from '../literal/index' import { Number, type TNumber } from '../number/index' +import { Computed, TComputed } from '../computed/index' +import { Ref, type TRef } from '../ref/index' import { KeyOfPropertyKeys, type TKeyOfPropertyKeys } from './keyof-property-keys' import { UnionEvaluated, type TUnionEvaluated } from '../union/index' import { KeyOfFromMappedResult, type TKeyOfFromMappedResult } from './keyof-from-mapped-result' @@ -40,46 +42,72 @@ import { KeyOfFromMappedResult, type TKeyOfFromMappedResult } from './keyof-from // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsMappedResult } from '../guard/kind' +import { IsMappedResult, IsRef, IsComputed } from '../guard/kind' +// ------------------------------------------------------------------ +// FromComputed +// ------------------------------------------------------------------ +// prettier-ignore +type TFromComputed = Ensure< + TComputed<'KeyOf', [TComputed]> +> +// prettier-ignore +function FromComputed(target: Target, parameters: Parameters): TFromComputed { + return Computed('KeyOf', [Computed(target, parameters)]) as never +} +// ------------------------------------------------------------------ +// FromRef +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRef = Ensure< + TComputed<'KeyOf', [TRef]> +> +// prettier-ignore +function FromRef($ref: Ref): TFromRef { + return Computed('KeyOf', [Ref($ref)]) as never +} +// ------------------------------------------------------------------ +// KeyOfFromType +// ------------------------------------------------------------------ +// prettier-ignore +/** `[Internal]` Used by KeyOfFromMappedResult */ +export type TKeyOfFromType, + PropertyKeyTypes extends TSchema[] = TKeyOfPropertyKeysToRest, + Result = TUnionEvaluated +> = Ensure +// prettier-ignore +function KeyOfFromType(type: Type, options?: SchemaOptions): TKeyOfFromType { + const propertyKeys = KeyOfPropertyKeys(type) as PropertyKey[] + const propertyKeyTypes = KeyOfPropertyKeysToRest(propertyKeys) + const result = UnionEvaluated(propertyKeyTypes) + return CreateType(result, options) as never +} // ------------------------------------------------------------------ // FromPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -export type TKeyOfPropertyKeysToRest = ( - T extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] +export type TKeyOfPropertyKeysToRest = ( + PropertyKeys extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] ? L extends '[number]' - ? TKeyOfPropertyKeysToRest - : TKeyOfPropertyKeysToRest>]> - : Acc + ? TKeyOfPropertyKeysToRest + : TKeyOfPropertyKeysToRest>]> + : Result ) // prettier-ignore -export function KeyOfPropertyKeysToRest(T: [...T]): TKeyOfPropertyKeysToRest { - return T.map(L => L === '[number]' ? Number() : Literal(L as TLiteralValue)) as never +export function KeyOfPropertyKeysToRest(propertyKeys: [...PropertyKeys]): TKeyOfPropertyKeysToRest { + return propertyKeys.map(L => L === '[number]' ? Number() : Literal(L as TLiteralValue)) as never } // ------------------------------------------------------------------ -// KeyOfTypeResolve +// TKeyOf // ------------------------------------------------------------------ // prettier-ignore -export type TKeyOf< - T extends TSchema, - K extends PropertyKey[] = TKeyOfPropertyKeys, - S extends TSchema[] = TKeyOfPropertyKeysToRest, - U = TUnionEvaluated -> = ( - Ensure +export type TKeyOf = ( + Type extends TComputed ? TFromComputed : + Type extends TRef ? TFromRef : + Type extends TMappedResult ? TKeyOfFromMappedResult : + TKeyOfFromType ) /** `[Json]` Creates a KeyOf type */ -export function KeyOf(T: T, options?: SchemaOptions): TKeyOfFromMappedResult -/** `[Json]` Creates a KeyOf type */ -export function KeyOf(T: T, options?: SchemaOptions): TKeyOf -/** `[Json]` Creates a KeyOf type */ -export function KeyOf(T: TSchema, options?: SchemaOptions): never { - if (IsMappedResult(T)) { - return KeyOfFromMappedResult(T, options) as never - } else { - const K = KeyOfPropertyKeys(T) - const S = KeyOfPropertyKeysToRest(K) - const U = UnionEvaluated(S) - return CreateType(U, options) as never - } +export function KeyOf(type: Type, options?: SchemaOptions): TKeyOf { + return (IsComputed(type) ? FromComputed(type.target, type.parameters) : IsRef(type) ? FromRef(type.$ref) : IsMappedResult(type) ? KeyOfFromMappedResult(type, options) : KeyOfFromType(type, options)) as never } diff --git a/src/type/module/compute.ts b/src/type/module/compute.ts new file mode 100644 index 000000000..47bf60851 --- /dev/null +++ b/src/type/module/compute.ts @@ -0,0 +1,402 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { CreateType } from '../create/index' +import { Ensure, Evaluate } from '../helpers/index' +import { type TSchema } from '../schema/index' +import { Array, type TArray } from '../array/index' +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' +import { KeyOf, type TKeyOf } from '../keyof/index' +import { Object, type TObject, type TProperties } from '../object/index' +import { Omit, type TOmit } from '../omit/index' +import { Pick, type TPick } from '../pick/index' +import { Never, type TNever } from '../never/index' +import { Partial, TPartial } from '../partial/index' +import { Record, type TRecordOrObject } from '../record/index' +import { type TRef } from '../ref/index' +import { Required, TRequired } from '../required/index' +import { Tuple, type TTuple } from '../tuple/index' +import { Union, type TUnion, type TUnionEvaluated } from '../union/index' + +// ------------------------------------------------------------------ +// KindGuard +// ------------------------------------------------------------------ +import * as KindGuard from '../guard/kind' + +// ------------------------------------------------------------------ +// DerefParameters +// +// Dereferences TComputed parameters. It is important to note that +// dereferencing anything other than these parameters may result +// inference and evaluation problems, potentially resulting in a +// stack overflow. All open TRef types must be preserved !!! +// +// ------------------------------------------------------------------ +// prettier-ignore +type TDerefParameters = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? Left extends TRef + ? TDerefParameters]> + : TDerefParameters]> + : Result +) +// prettier-ignore +function DerefParameters(moduleProperties: ModuleProperties, types: [...Types]): TFromRest { + return types.map((type) => { + return KindGuard.IsRef(type) + ? Deref(moduleProperties, type.$ref) + : FromType(moduleProperties, type) + }) as never +} +// prettier-ignore +type TDeref + ? TDeref + : TFromType + : TNever +)> = Result +// prettier-ignore +function Deref(moduleProperties: ModuleProperties, ref: Ref): TDeref { + return ( + ref in moduleProperties + ? KindGuard.IsRef(moduleProperties[ref]) + ? Deref(moduleProperties, moduleProperties[ref].$ref) + : FromType(moduleProperties, moduleProperties[ref]) + : Never() + ) as never +} +// ------------------------------------------------------------------ +// Awaited +// ------------------------------------------------------------------ +// prettier-ignore +type TFromAwaited = ( + Parameters extends [infer T0 extends TSchema] ? TAwaited : never +) +// prettier-ignore +function FromAwaited(parameters: Parameters): TFromAwaited { + 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 +type TFromKeyOf = ( + Parameters extends [infer T0 extends TSchema] ? TKeyOf : never +) +// prettier-ignore +function FromKeyOf(parameters: Parameters): TFromAwaited { + return KeyOf(parameters[0]) as never +} +// ------------------------------------------------------------------ +// Partial +// ------------------------------------------------------------------ +// prettier-ignore +type TFromPartial = ( + Parameters extends [infer T0 extends TSchema] ? TPartial : never +) +// prettier-ignore +function FromPartial(parameters: Parameters): TFromPartial { + return Partial(parameters[0]) as never +} +// ------------------------------------------------------------------ +// Omit +// ------------------------------------------------------------------ +// prettier-ignore +type TFromOmit = ( + Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] ? TOmit : never +) +// prettier-ignore +function FromOmit(parameters: Parameters): TFromPick { + return Omit(parameters[0], parameters[1]) as never +} +// ------------------------------------------------------------------ +// Pick +// ------------------------------------------------------------------ +// prettier-ignore +type TFromPick = ( + Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] ? TPick : never +) +// prettier-ignore +function FromPick(parameters: Parameters): TFromPick { + return Pick(parameters[0], parameters[1]) as never +} +// ------------------------------------------------------------------ +// Record +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRecord = ( + Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] ? TRecordOrObject : never +) +// prettier-ignore +function FromRecord(parameters: Parameters): TFromPick { + return Record(parameters[0], parameters[1]) as never +} +// ------------------------------------------------------------------ +// Required +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRequired = ( + Parameters extends [infer T0 extends TSchema] ? TRequired : never +) +// prettier-ignore +function FromRequired(parameters: Parameters): TFromPick { + return Required(parameters[0]) as never +} +// ------------------------------------------------------------------ +// Computed +// ------------------------------------------------------------------ +// prettier-ignore +type TFromComputed +> = ( + Target extends 'Awaited' ? TFromAwaited : + Target extends 'Index' ? TFromIndex : + Target extends 'KeyOf' ? TFromKeyOf : + Target extends 'Partial' ? TFromPartial : + Target extends 'Omit' ? TFromOmit : + Target extends 'Pick' ? TFromPick : + Target extends 'Record' ? TFromRecord : + Target extends 'Required' ? TFromRequired : + TNever +) +// prettier-ignore +function FromComputed(moduleProperties: ModuleProperties, target: Target, parameters: Parameters): TFromComputed { + const dereferenced = DerefParameters(moduleProperties, parameters) + return ( + target === 'Awaited' ? FromAwaited(dereferenced) : + target === 'Index' ? FromIndex(dereferenced) : + target === 'KeyOf' ? FromKeyOf(dereferenced) : + target === 'Partial' ? FromPartial(dereferenced) : + target === 'Omit' ? FromOmit(dereferenced) : + target === 'Pick' ? FromPick(dereferenced) : + target === 'Record' ? FromRecord(dereferenced) : + target === 'Required' ? FromRequired(dereferenced) : + Never() + ) as never +} +// ------------------------------------------------------------------ +// Object +// ------------------------------------------------------------------ +// prettier-ignore +type TFromObject = Ensure +}>>> +function FromObject(moduleProperties: ModuleProperties, properties: Properties): TFromObject { + return Object( + globalThis.Object.keys(properties).reduce((result, key) => { + return { ...result, [key]: FromType(moduleProperties, properties[key]) as never } + }, {} as TProperties), + ) as never +} +// ------------------------------------------------------------------ +// Constructor +// ------------------------------------------------------------------ +// prettier-ignore +type TFromConstructor = ( + TConstructor, TFromType> +) +// prettier-ignore +function FromConstructor( + moduleProperties: ModuleProperties, + parameters: [...Parameters], + instanceType: InstanceType, +): TFromConstructor { + return Constructor(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, instanceType) as never) as never +} +// ------------------------------------------------------------------ +// Function +// ------------------------------------------------------------------ +// prettier-ignore +type TFromFunction = Ensure< + Ensure, TFromType>> +> +// prettier-ignore +function FromFunction( + moduleProperties: ModuleProperties, + parameters: [...Parameters], + returnType: ReturnType, +): TFromFunction { + return Function(FromRest(moduleProperties, parameters as never), FromType(moduleProperties, returnType) as never) as never +} +// ------------------------------------------------------------------ +// Tuple +// ------------------------------------------------------------------ +// prettier-ignore +type TFromTuple = ( + Ensure>> +) +function FromTuple(moduleProperties: ModuleProperties, types: [...Types]): TFromTuple { + return Tuple(FromRest(moduleProperties, types as never)) as never +} +// ------------------------------------------------------------------ +// Intersect +// ------------------------------------------------------------------ +// prettier-ignore +type TFromIntersect = ( + Ensure>> +) +function FromIntersect(moduleProperties: ModuleProperties, types: [...Types]): TFromIntersect { + return Intersect(FromRest(moduleProperties, types as never)) as never +} +// ------------------------------------------------------------------ +// Union +// ------------------------------------------------------------------ +// prettier-ignore +type TFromUnion = ( + Ensure>> +) +function FromUnion(moduleProperties: ModuleProperties, types: [...Types]): TFromUnion { + return Union(FromRest(moduleProperties, types as never)) as never +} +// ------------------------------------------------------------------ +// Array +// ------------------------------------------------------------------ +// prettier-ignore +type TFromArray = ( + Ensure>> +) +function FromArray(moduleProperties: ModuleProperties, type: Type): TFromArray { + return Array(FromType(moduleProperties, type)) +} +// ------------------------------------------------------------------ +// AsyncIterator +// ------------------------------------------------------------------ +// prettier-ignore +type TFromAsyncIterator = ( + TAsyncIterator> +) +function FromAsyncIterator(moduleProperties: ModuleProperties, type: Type): TFromAsyncIterator { + return AsyncIterator(FromType(moduleProperties, type)) +} +// ------------------------------------------------------------------ +// Iterator +// ------------------------------------------------------------------ +// prettier-ignore +type TFromIterator = ( + TIterator> +) +function FromIterator(moduleProperties: ModuleProperties, type: Type): TFromIterator { + return Iterator(FromType(moduleProperties, type)) +} +// ------------------------------------------------------------------ +// Rest +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRest = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? TFromRest]> + : Result +) +function FromRest(moduleProperties: ModuleProperties, types: [...Types]): TFromRest { + return types.map((type) => FromType(moduleProperties, type)) as never +} +// ------------------------------------------------------------------ +// Type +// ------------------------------------------------------------------ +// prettier-ignore +export type TFromType = ( + Type extends TComputed ? TFromComputed : + Type extends TObject ? TFromObject : + Type extends TConstructor ? TFromConstructor : + Type extends TFunction ? TFromFunction : + Type extends TTuple ? TFromTuple : + Type extends TIntersect ? TFromIntersect : + Type extends TUnion ? TFromUnion : + Type extends TArray ? TFromArray : + Type extends TAsyncIterator ? TFromAsyncIterator : + Type extends TIterator ? TFromIterator : + Type +) +// prettier-ignore +export function FromType(moduleProperties: ModuleProperties, type: Type): TFromType { + return ( + // 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) : + KindGuard.IsTuple(type)? CreateType(FromTuple(moduleProperties, type.items || []), type) : + KindGuard.IsIntersect(type) ? CreateType(FromIntersect(moduleProperties, type.allOf), type) : + KindGuard.IsUnion(type) ? CreateType(FromUnion(moduleProperties, type.anyOf), type) : + KindGuard.IsArray(type) ? CreateType(FromArray(moduleProperties, type.items), type) : + KindGuard.IsAsyncIterator(type) ? CreateType(FromAsyncIterator(moduleProperties, type.items), type) : + KindGuard.IsIterator(type) ? CreateType(FromIterator(moduleProperties, type.items), type) : + type + ) as never +} +// ------------------------------------------------------------------ +// ComputeType +// ------------------------------------------------------------------ +// prettier-ignore +export type TComputeType = ( + Key extends keyof ModuleProperties + ? TFromType + : TNever +) +// prettier-ignore +export function ComputeType(moduleProperties: ModuleProperties, key: Key): TComputeType { + return ( + key in moduleProperties + ? FromType(moduleProperties, moduleProperties[key as keyof ModuleProperties]) + : Never() + ) as never +} +// ------------------------------------------------------------------ +// ComputeModuleProperties +// ------------------------------------------------------------------ +// prettier-ignore +export type TComputeModuleProperties = Evaluate<{ + [Key in keyof ModuleProperties]: TComputeType +}> +// prettier-ignore +export function ComputeModuleProperties(moduleProperties: ModuleProperties): TComputeModuleProperties { + return globalThis.Object.getOwnPropertyNames(moduleProperties).reduce((result, key) => { + return {...result, [key]: ComputeType(moduleProperties, key) } + }, {} as TProperties) as never +} diff --git a/src/type/module/infer.ts b/src/type/module/infer.ts new file mode 100644 index 000000000..ff37ce0a7 --- /dev/null +++ b/src/type/module/infer.ts @@ -0,0 +1,162 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import { Ensure, Evaluate } from '../helpers/index' +import { TSchema } from '../schema/index' +import { TArray } from '../array/index' +import { TAsyncIterator } from '../async-iterator/index' +import { TConstructor } from '../constructor/index' +import { TFunction } from '../function/index' +import { TIntersect } from '../intersect/index' +import { TIterator } from '../iterator/index' +import { TObject, TProperties } from '../object/index' +import { TOptional } from '../optional/index' +import { TReadonly } from '../readonly/index' +import { TRef } from '../ref/index' +import { TTuple } from '../tuple/index' +import { TUnion } from '../union/index' +import { Static } from '../static/index' + +// ------------------------------------------------------------------ +// Array +// ------------------------------------------------------------------ +// prettier-ignore +type TInferArray = ( + Ensure>> +) +// ------------------------------------------------------------------ +// AsyncIterator +// ------------------------------------------------------------------ +// prettier-ignore +type TInferAsyncIterator = ( + Ensure>> +) +// ------------------------------------------------------------------ +// Constructor +// ------------------------------------------------------------------ +// prettier-ignore +type TInferConstructor = Ensure< + new (...args: TInferTuple) => TInfer +> +// ------------------------------------------------------------------ +// Function +// ------------------------------------------------------------------ +// prettier-ignore +type TInferFunction = Ensure< + (...args: TInferTuple) => TInfer +> +// ------------------------------------------------------------------ +// Iterator +// ------------------------------------------------------------------ +// prettier-ignore +type TInferIterator = ( + Ensure>> +) +// ------------------------------------------------------------------ +// Intersect +// ------------------------------------------------------------------ +// prettier-ignore +type TInferIntersect = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TInferIntersect> + : Result +) +// ------------------------------------------------------------------ +// Object +// ------------------------------------------------------------------ +type ReadonlyOptionalPropertyKeys = { [K in keyof Properties]: Properties[K] extends TReadonly ? (Properties[K] extends TOptional ? K : never) : never }[keyof Properties] +type ReadonlyPropertyKeys = { [K in keyof Source]: Source[K] extends TReadonly ? (Source[K] extends TOptional ? never : K) : never }[keyof Source] +type OptionalPropertyKeys = { [K in keyof Source]: Source[K] extends TOptional ? (Source[K] extends TReadonly ? never : K) : never }[keyof Source] +type RequiredPropertyKeys = keyof Omit | ReadonlyPropertyKeys | OptionalPropertyKeys> +// prettier-ignore +type InferPropertiesWithModifiers> = Evaluate<( + Readonly>>> & + Readonly>> & + Partial>> & + Required>> +)> +// prettier-ignore +type InferProperties = InferPropertiesWithModifiers +}> +// prettier-ignore +type TInferObject = ( + InferProperties +) +// ------------------------------------------------------------------ +// Tuple +// ------------------------------------------------------------------ +// prettier-ignore +type TInferTuple = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TInferTuple]> + : Result +) +// ------------------------------------------------------------------ +// Ref +// ------------------------------------------------------------------ +// prettier-ignore +type TInferRef = ( + Ref extends keyof ModuleProperties ? TInfer : unknown +) +// ------------------------------------------------------------------ +// Union +// ------------------------------------------------------------------ +// prettier-ignore +type TInferUnion = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TInferUnion> + : Result +) +// ------------------------------------------------------------------ +// Infer +// ------------------------------------------------------------------ +// prettier-ignore +type TInfer = ( + Type extends TArray ? TInferArray : + Type extends TAsyncIterator ? TInferAsyncIterator : + Type extends TConstructor ? TInferConstructor : + Type extends TFunction ? TInferFunction : + Type extends TIntersect ? TInferIntersect : + Type extends TIterator ? TInferIterator : + Type extends TObject ? TInferObject : + Type extends TRef ? TInferRef : + Type extends TTuple ? TInferTuple : + Type extends TUnion ? TInferUnion : + Static +) +// ------------------------------------------------------------------ +// InferImport +// ------------------------------------------------------------------ +/** Inference Path for Imports. This type is used to compute TImport `static` */ +// prettier-ignore +export type TInferType = ( + Key extends keyof ModuleProperties + ? TInfer + : never +) diff --git a/src/type/module/module.ts b/src/type/module/module.ts index 3fef83c80..cf5cfd8ce 100644 --- a/src/type/module/module.ts +++ b/src/type/module/module.ts @@ -26,124 +26,19 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import { Ensure } from '../helpers/index' import { CreateType } from '../create/index' import { Kind } from '../symbols/index' import { SchemaOptions, TSchema } from '../schema/index' -import { TObject, TProperties } from '../object/index' -import { TConstructor } from '../constructor/index' -import { TFunction } from '../function/index' -import { TTuple } from '../tuple/index' -import { TIntersect } from '../intersect/index' -import { TUnion } from '../union/index' -import { TArray } from '../array/index' -import { TAsyncIterator } from '../async-iterator/index' -import { TIterator } from '../iterator/index' -import { TLiteral, TLiteralValue } from '../literal/index' -import { TAny } from '../any/index' -import { TBigInt } from '../bigint/index' -import { TBoolean } from '../boolean/index' -import { TDate } from '../date/index' -import { TInteger } from '../integer/index' -import { TNever } from '../never/index' -import { TNumber } from '../number/index' -import { TNull } from '../null/index' -import { TRef } from '../ref/index' -import { TRegExp } from '../regexp/index' -import { TString } from '../string/index' -import { TSymbol } from '../symbol/index' -import { TTemplateLiteral, TTemplateLiteralKind } from '../template-literal/index' -import { TUint8Array } from '../uint8array/index' -import { TUndefined } from '../undefined/index' -import { TUnknown } from '../unknown/index' -import { TVoid } from '../void/index' +import { TProperties } from '../object/index' import { Static } from '../static/index' // ------------------------------------------------------------------ -// Infer +// Module Infrastructure Types // ------------------------------------------------------------------ -// prettier-ignore -type InferImport = ( - Infer -) -// prettier-ignore -type InferRef = ( - Ref extends keyof Properties ? Infer : never -) -// prettier-ignore -type InferObject = { - [K in keyof Properties]: Infer -} & {} -// prettier-ignore -type InferConstructor = Ensure< - new (...args: InferTuple) => Infer -> -// prettier-ignore -type InferFunction = Ensure< - (...args: InferTuple) => Infer -> -// prettier-ignore -type InferTuple = ( - Types extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? InferTuple]> - : Result -) -// prettier-ignore -type InferIntersect = ( - Types extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? InferIntersect> - : Result -) -// prettier-ignore -type InferUnion = ( - Types extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? InferUnion> - : Result -) -// prettier-ignore -type InferArray = ( - Ensure>> -) -// prettier-ignore -type InferAsyncIterator = ( - Ensure>> -) -// prettier-ignore -type InferIterator = ( - Ensure>> -) -// prettier-ignore -type Infer = ( - Type extends TImport ? InferImport : - Type extends TRef ? InferRef : - Type extends TObject ? InferObject : - Type extends TConstructor ? InferConstructor : - Type extends TFunction ? InferFunction : - Type extends TTuple ? InferTuple : - Type extends TIntersect ? InferIntersect : - Type extends TUnion ? InferUnion : - Type extends TArray ? InferArray : - Type extends TAsyncIterator ? InferAsyncIterator : - Type extends TIterator ? InferIterator : - Type extends TTemplateLiteral ? Static> : - Type extends TLiteral ? S : - Type extends TAny ? any : - Type extends TBigInt ? bigint : - Type extends TBoolean ? boolean : - Type extends TDate ? Date : - Type extends TInteger ? number : - Type extends TNever ? never : - Type extends TNumber ? number : - Type extends TRegExp ? string : - Type extends TString ? string : - Type extends TSymbol ? symbol : - Type extends TNull ? null : - Type extends TUint8Array ? Uint8Array : - Type extends TUndefined ? undefined : - Type extends TUnknown ? unknown : - Type extends TVoid ? void : - never -) +import { type TComputeType } from './compute' +import { ComputeModuleProperties, TComputeModuleProperties } from './compute' +import { TInferType } from './infer' + // ------------------------------------------------------------------ // Definitions // ------------------------------------------------------------------ @@ -157,30 +52,30 @@ export interface TDefinitions extends TSch // prettier-ignore export interface TImport extends TSchema { [Kind]: 'Import' - static: InferImport - $defs: ModuleProperties + static: TInferType + $defs: TComputeModuleProperties $ref: Key } // ------------------------------------------------------------------ // Module // ------------------------------------------------------------------ // prettier-ignore -export class TModule { - constructor(private readonly $defs: Properties, private readonly options: SchemaOptions = {}) {} - - /** `[Json]` Returns the Type definitions for this module */ - public Defs(): TDefinitions { - return CreateType({ $defs: this.ResolveDefinitionsWithIdentifiers() }, this.options) as never +export class TModule> { + private readonly $defs: ComputedModuleProperties + constructor($defs: ModuleProperties) { + const computed = ComputeModuleProperties($defs) + const identified = this.WithIdentifiers(computed as never) + this.$defs = identified as never } /** `[Json]` Imports a Type by Key. */ - public Import(key: Key, options?: SchemaOptions): TImport { - return CreateType({ [Kind]: 'Import', $defs: this.ResolveDefinitionsWithIdentifiers(), $ref: key }, options) as never + public Import(key: Key, options?: SchemaOptions): TImport { + return CreateType({ [Kind]: 'Import', $defs: this.$defs, $ref: key }, options) as never } - /** `[Internal]` For each definition, assign an `$id` property. */ - private ResolveDefinitionsWithIdentifiers() { - return globalThis.Object.getOwnPropertyNames(this.$defs).reduce((Result, Key) => ( - { ...Result, [Key]: { ...this.$defs[Key], $id: Key }} - ), {}) + // prettier-ignore + private WithIdentifiers($defs: ComputedModuleProperties): ComputedModuleProperties { + return globalThis.Object.getOwnPropertyNames($defs).reduce((result, key) => { + return { ...result, [key]: { ...$defs[key], $id: key }} + }, {}) as never } } /** `[Json]` Creates a Type Definition Module. */ 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/omit/omit-from-mapped-key.ts b/src/type/omit/omit-from-mapped-key.ts index 5eeb68660..2a2a4ae94 100644 --- a/src/type/omit/omit-from-mapped-key.ts +++ b/src/type/omit/omit-from-mapped-key.ts @@ -36,77 +36,52 @@ import { Clone } from '../clone/value' // FromPropertyKey // ------------------------------------------------------------------ // prettier-ignore -type TFromPropertyKey< - T extends TSchema, - K extends PropertyKey, -> = { - [_ in K]: TOmit - } +type TFromPropertyKey = { + [_ in Key]: TOmit +} // prettier-ignore -function FromPropertyKey< - T extends TSchema, - K extends PropertyKey, ->(T: T, K: K, options?: SchemaOptions): TFromPropertyKey { - return { - [K]: Omit(T, [K], Clone(options)) - } as never +function FromPropertyKey(type: Type, key: Key, options?: SchemaOptions): TFromPropertyKey { + return { [key]: Omit(type, [key], Clone(options)) } as never } // ------------------------------------------------------------------ // FromPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -type TFromPropertyKeys< - T extends TSchema, - K extends PropertyKey[], - Acc extends TProperties = {} -> = ( - K extends [infer LK extends PropertyKey, ...infer RK extends PropertyKey[]] - ? TFromPropertyKeys> - : Acc +type TFromPropertyKeys = ( + PropertyKeys extends [infer LK extends PropertyKey, ...infer RK extends PropertyKey[]] + ? TFromPropertyKeys> + : Result ) // prettier-ignore -function FromPropertyKeys< - T extends TSchema, - K extends PropertyKey[] ->(T: T, K: [...K], options?: SchemaOptions): TFromPropertyKeys { - return K.reduce((Acc, LK) => { - return { ...Acc, ...FromPropertyKey(T, LK, options) } +function FromPropertyKeys(type: Type, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromPropertyKeys { + return propertyKeys.reduce((Acc, LK) => { + return { ...Acc, ...FromPropertyKey(type, LK, options) } }, {} as TProperties) as never } // ------------------------------------------------------------------ // FromMappedKey // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedKey< - T extends TSchema, - K extends TMappedKey, -> = ( - TFromPropertyKeys +type TFromMappedKey = ( + TFromPropertyKeys ) // prettier-ignore -function FromMappedKey< - T extends TSchema, - K extends TMappedKey, ->(T: T, K: K, options?: SchemaOptions): TFromMappedKey { - return FromPropertyKeys(T, K.keys, options) as never +function FromMappedKey(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TFromMappedKey { + return FromPropertyKeys(type, mappedKey.keys, options) as never } // ------------------------------------------------------------------ // OmitFromMappedKey // ------------------------------------------------------------------ // prettier-ignore -export type TOmitFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TFromMappedKey +export type TOmitFromMappedKey > = ( - TMappedResult

+ TMappedResult ) // prettier-ignore -export function OmitFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TFromMappedKey ->(T: T, K: K, options?: SchemaOptions): TMappedResult

{ - const P = FromMappedKey(T, K, options) - return MappedResult(P) as never +export function OmitFromMappedKey +>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedResult { + const properties = FromMappedKey(type, mappedKey, options) + return MappedResult(properties) as never } diff --git a/src/type/omit/omit-from-mapped-result.ts b/src/type/omit/omit-from-mapped-result.ts index 205047ea8..5abac5f60 100644 --- a/src/type/omit/omit-from-mapped-result.ts +++ b/src/type/omit/omit-from-mapped-result.ts @@ -37,55 +37,43 @@ import { Clone } from '../clone/value' // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties< - P extends TProperties, - K extends PropertyKey[], -> = ( - { [K2 in keyof P]: TOmit } +type TFromProperties = ( + { [K2 in keyof Properties]: TOmit } ) // prettier-ignore -function FromProperties< - P extends TProperties, - K extends PropertyKey[], ->(P: P, K: [...K], options?: SchemaOptions): TFromProperties { - const Acc = {} as TProperties - for(const K2 of globalThis.Object.getOwnPropertyNames(P)) Acc[K2] = Omit(P[K2], K, Clone(options)) - return Acc as never +function FromProperties(properties: Properties, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromProperties { + const result = {} as TProperties + for(const K2 of globalThis.Object.getOwnPropertyNames(properties)) result[K2] = Omit(properties[K2], propertyKeys, Clone(options)) + return result as never } // ------------------------------------------------------------------ // FromMappedResult // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedResult< - R extends TMappedResult, - K extends PropertyKey[], -> = ( - Evaluate> +type TFromMappedResult = ( + Evaluate> ) // prettier-ignore -function FromMappedResult< - R extends TMappedResult, - K extends PropertyKey[] ->(R: R, K: [...K], options?: SchemaOptions): TFromMappedResult { - return FromProperties(R.properties, K, options) as never +function FromMappedResult(mappedResult: MappedResult, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromMappedResult { + return FromProperties(mappedResult.properties, propertyKeys, options) as never } // ------------------------------------------------------------------ // TOmitFromMappedResult // ------------------------------------------------------------------ // prettier-ignore export type TOmitFromMappedResult< - T extends TMappedResult, - K extends PropertyKey[], - P extends TProperties = TFromMappedResult + MappedResult extends TMappedResult, + PropertyKeys extends PropertyKey[], + Properties extends TProperties = TFromMappedResult > = ( - Ensure> + Ensure> ) // prettier-ignore export function OmitFromMappedResult< - R extends TMappedResult, - K extends PropertyKey[], - P extends TProperties = TFromMappedResult ->(R: R, K: [...K], options?: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(R, K, options) - return MappedResult(P) as never + MappedResult extends TMappedResult, + PropertyKeys extends PropertyKey[], + Properties extends TProperties = TFromMappedResult +>(mappedResult: MappedResult, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TMappedResult { + const properties = FromMappedResult(mappedResult, propertyKeys, options) + return MappedResult(properties) as never } diff --git a/src/type/omit/omit.ts b/src/type/omit/omit.ts index 99a947706..d52a8b477 100644 --- a/src/type/omit/omit.ts +++ b/src/type/omit/omit.ts @@ -28,112 +28,167 @@ THE SOFTWARE. import { CreateType } from '../create/type' import { Discard } from '../discard/discard' +import { TransformKind } from '../symbols/symbols' import type { SchemaOptions, TSchema } from '../schema/index' import type { TupleToUnion, Evaluate, Ensure } from '../helpers/index' import { type TRecursive } from '../recursive/index' import type { TMappedKey, TMappedResult } from '../mapped/index' +import { Computed, TComputed } from '../computed/index' +import { Literal, TLiteral, TLiteralValue } from '../literal/index' +import { IndexPropertyKeys, type TIndexPropertyKeys } from '../indexed/index' import { Intersect, type TIntersect } from '../intersect/index' import { Union, type TUnion } from '../union/index' import { Object, type TObject, type TProperties } from '../object/index' -import { IndexPropertyKeys, type TIndexPropertyKeys } from '../indexed/index' +import { type TRef } from '../ref/index' + +// ------------------------------------------------------------------ +// Mapped +// ------------------------------------------------------------------ import { OmitFromMappedKey, type TOmitFromMappedKey } from './omit-from-mapped-key' import { OmitFromMappedResult, type TOmitFromMappedResult } from './omit-from-mapped-result' -import { TransformKind } from '../symbols/symbols' + // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsMappedKey, IsIntersect, IsUnion, IsObject, IsSchema, IsMappedResult } from '../guard/kind' +import { IsMappedKey, IsIntersect, IsUnion, IsObject, IsSchema, IsMappedResult, IsLiteralValue, IsRef } from '../guard/kind' +import { IsArray as IsArrayValue } from '../guard/value' // ------------------------------------------------------------------ // FromIntersect // ------------------------------------------------------------------ // prettier-ignore -type TFromIntersect = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromIntersect]> - : Acc +type TFromIntersect = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromIntersect]> + : Result ) // prettier-ignore -function FromIntersect(T: T, K: K) { - return T.map((T) => OmitResolve(T, K)) as never +function FromIntersect(types: Types, propertyKeys: PropertyKeys) { + return types.map((type) => OmitResolve(type, propertyKeys)) as never } // ------------------------------------------------------------------ // FromUnion // ------------------------------------------------------------------ // prettier-ignore -type TFromUnion = ( +type TFromUnion = ( T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromUnion]> - : Acc + ? TFromUnion]> + : Result ) // prettier-ignore -function FromUnion(T: T, K: K) { - return T.map((T) => OmitResolve(T, K)) as never +function FromUnion(types: Types, propertyKeys: PropertyKeys) { + return types.map((type) => OmitResolve(type, propertyKeys)) as never } // ------------------------------------------------------------------ // FromProperty // ------------------------------------------------------------------ // prettier-ignore -function FromProperty, K extends PropertyKey>(T: T, K: K): TProperties { - const { [K]: _, ...R } = T +function FromProperty(properties: Properties, key: Key): TProperties { + const { [key]: _, ...R } = properties return R } // prettier-ignore -type TFromProperties> = Evaluate> +type TFromProperties> = ( + Evaluate> +) // prettier-ignore -function FromProperties(T: T, K: K) { - return K.reduce((T, K2) => FromProperty(T, K2), T as TProperties) +function FromProperties(properties: Properties, propertyKeys: PropertyKeys) { + return propertyKeys.reduce((T, K2) => FromProperty(T, K2), properties as TProperties) } // ------------------------------------------------------------------ // FromObject // ------------------------------------------------------------------ // prettier-ignore -type TFromObject = Ensure +type TFromObject = Ensure )>> // prettier-ignore -function FromObject(T: T, K: K): TFromObject { - const options = Discard(T, [TransformKind, '$id', 'required', 'properties']) - const properties = FromProperties(T['properties'], K) - return Object(properties, options) as never +function FromObject(properties: Properties, propertyKeys: PropertyKeys): TFromObject { + const options = Discard(properties, [TransformKind, '$id', 'required', 'properties']) + const omittedProperties = FromProperties(properties['properties'], propertyKeys) + return Object(omittedProperties, options) as never } // ------------------------------------------------------------------ -// OmitResolve +// UnionFromPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -function OmitResolve(T: T, K: [...K]): TOmit { - return ( - IsIntersect(T) ? Intersect(FromIntersect(T.allOf, K)) : - IsUnion(T) ? Union(FromUnion(T.anyOf, K)) : - IsObject(T) ? FromObject(T, K) : - Object({}) - ) as never +type TUnionFromPropertyKeys = ( + PropertyKeys extends [infer Key extends PropertyKey, ...infer Rest extends PropertyKey[]] + ? Key extends TLiteralValue + ? TUnionFromPropertyKeys]> + : TUnionFromPropertyKeys + : TUnion +) +// prettier-ignore +function UnionFromPropertyKeys(propertyKeys: PropertyKeys): TUnionFromPropertyKeys { + const result = propertyKeys.reduce((result, key) => IsLiteralValue(key) ? [...result, Literal(key)]: result, [] as TLiteral[]) + return Union(result) as never } +// ------------------------------------------------------------------ +// TOmitResolve +// ------------------------------------------------------------------ // prettier-ignore -export type TOmit = ( - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TFromObject, K> : +export type TOmitResolve = ( + Properties extends TRecursive ? TRecursive> : + Properties extends TIntersect ? TIntersect> : + Properties extends TUnion ? TUnion> : + Properties extends TObject ? TFromObject, PropertyKeys> : TObject<{}> ) +// prettier-ignore +function OmitResolve(properties: Properties, propertyKeys: [...PropertyKeys]): TOmitResolve { + return ( + IsIntersect(properties) ? Intersect(FromIntersect(properties.allOf, propertyKeys)) : + IsUnion(properties) ? Union(FromUnion(properties.anyOf, propertyKeys)) : + IsObject(properties) ? FromObject(properties, propertyKeys) : + Object({}) + ) as never +} // ------------------------------------------------------------------ // TOmit +// +// This mapping logic is to overly complex because of the decision +// to use PropertyKey[] as the default selector. The PropertyKey[] +// did make TMapped types simpler to implement, but a non-TSchema +// selector makes supporting TComputed awkward as it requires +// generalization via TSchema. This type should be reimplemented +// in the next major revision to support TSchema as the primary +// selector. +// // ------------------------------------------------------------------ -/** `[Json]` Constructs a type whose keys are omitted from the given type */ -export function Omit(T: T, K: [...K], options?: SchemaOptions): TOmitFromMappedResult -/** `[Json]` Constructs a type whose keys are omitted from the given type */ -export function Omit(T: T, K: K, options?: SchemaOptions): TOmitFromMappedKey -/** `[Json]` Constructs a type whose keys are omitted from the given type */ -export function Omit>(T: T, K: K, options?: SchemaOptions): TOmit -/** `[Json]` Constructs a type whose keys are omitted from the given type */ -export function Omit(T: T, K: readonly [...K], options?: SchemaOptions): TOmit -export function Omit(T: TSchema, K: any, options?: SchemaOptions): any { - // mapped - if (IsMappedKey(K)) return OmitFromMappedKey(T, K, options) - if (IsMappedResult(T)) return OmitFromMappedResult(T, K, options) - // non-mapped - const I = IsSchema(K) ? IndexPropertyKeys(K) : (K as string[]) - // special: mapping types require overridable options - return CreateType({ ...OmitResolve(T, I), ...options }) +// prettier-ignore (do not export this type) +type TResolvePropertyKeys = Key extends TSchema ? TIndexPropertyKeys : Key +// prettier-ignore (do not export this type) +type TResolveTypeKey = Key extends PropertyKey[] ? TUnionFromPropertyKeys : Key +// prettier-ignore +export type TOmit = ( + Type extends TMappedResult ? TOmitFromMappedResult> : + Key extends TMappedKey ? TOmitFromMappedKey : + [IsTypeRef, IsKeyRef] extends [true, true] ? TComputed<'Omit', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [false, true] ? TComputed<'Omit', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [true, false] ? TComputed<'Omit', [Type, TResolveTypeKey]> : + TOmitResolve> +) +/** `[Json]` Constructs a type whose keys are picked from the given type */ +export function Omit(type: Type, key: readonly [...Key], options?: SchemaOptions): TOmit +/** `[Json]` Constructs a type whose keys are picked from the given type */ +export function Omit(type: Type, key: Key, options?: SchemaOptions): TOmit +/** `[Json]` Constructs a type whose keys are picked from the given type */ +// prettier-ignore +export function Omit(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(type) ? OmitFromMappedResult(type, propertyKeys, options) : + IsMappedKey(key) ? OmitFromMappedKey(type, key, options) : + (isTypeRef && isKeyRef) ? Computed('Omit', [type, typeKey], options) : + (!isTypeRef && isKeyRef) ? Computed('Omit', [type, typeKey], options) : + (isTypeRef && !isKeyRef) ? Computed('Omit', [type, typeKey], options) : + CreateType({ ...OmitResolve(type, propertyKeys), ...options }) + ) as never } diff --git a/src/type/partial/partial.ts b/src/type/partial/partial.ts index 21bd5cf3e..3cfb48724 100644 --- a/src/type/partial/partial.ts +++ b/src/type/partial/partial.ts @@ -31,73 +31,99 @@ import type { TSchema, SchemaOptions } from '../schema/index' import type { Evaluate, Ensure } from '../helpers/index' import type { TMappedResult } from '../mapped/index' import { type TReadonlyOptional } from '../readonly-optional/index' +import { type TComputed, Computed } from '../computed/index' import { type TOptional, Optional } from '../optional/index' import { type TReadonly } from '../readonly/index' import { type TRecursive } from '../recursive/index' import { type TObject, type TProperties, Object } from '../object/index' import { type TIntersect, Intersect } from '../intersect/index' import { type TUnion, Union } from '../union/index' +import { type TRef, Ref } from '../ref/index' import { Discard } from '../discard/index' import { TransformKind } from '../symbols/index' - import { PartialFromMappedResult, type TPartialFromMappedResult } from './partial-from-mapped-result' // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsMappedResult, IsIntersect, IsUnion, IsObject } from '../guard/kind' +import { IsMappedResult, IsIntersect, IsUnion, IsObject, IsRef, IsComputed } from '../guard/kind' + // ------------------------------------------------------------------ -// FromRest +// FromComputed // ------------------------------------------------------------------ // prettier-ignore -type TFromRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest]> - : Acc -) +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 -function FromRest(T: [...T]): TFromRest { - return T.map(L => PartialResolve(L)) as never +type TFromRef = Ensure< + TComputed<'Partial', [TRef]> +> +// prettier-ignore +function FromRef($ref: Ref): TFromRef { + return Computed('Partial', [Ref($ref)]) as never } // ------------------------------------------------------------------ // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties = Evaluate<{ - [K in keyof T]: - T[K] extends (TReadonlyOptional) ? TReadonlyOptional : - T[K] extends (TReadonly) ? TReadonlyOptional : - T[K] extends (TOptional) ? TOptional : - TOptional +type TFromProperties = Evaluate<{ + [K in keyof Properties]: + Properties[K] extends (TReadonlyOptional) ? TReadonlyOptional : + Properties[K] extends (TReadonly) ? TReadonlyOptional : + Properties[K] extends (TOptional) ? TOptional : + TOptional }> // prettier-ignore -function FromProperties(T: T): TFromProperties { - const Acc = {} as TProperties - for(const K of globalThis.Object.getOwnPropertyNames(T)) Acc[K] = Optional(T[K]) - return Acc as never +function FromProperties(properties: Properties): TFromProperties { + const partialProperties = {} as TProperties + for(const K of globalThis.Object.getOwnPropertyNames(properties)) partialProperties[K] = Optional(properties[K]) + return partialProperties as never } // ------------------------------------------------------------------ // FromObject // ------------------------------------------------------------------ // prettier-ignore -type TFromObject = Ensure = Ensure )>> // prettier-ignore -function FromObject(T: T): TFromObject { +function FromObject(T: Type): TFromObject { const options = Discard(T, [TransformKind, '$id', 'required', 'properties']) const properties = FromProperties(T['properties']) return Object(properties, options) as never } // ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRest = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromRest]> + : Result +) +// prettier-ignore +function FromRest(types: [...Types]): TFromRest { + return types.map(type => PartialResolve(type)) as never +} +// ------------------------------------------------------------------ // PartialResolve // ------------------------------------------------------------------ // prettier-ignore -function PartialResolve(T: T): TPartial { +function PartialResolve(type: Type): TPartial { return ( - IsIntersect(T) ? Intersect(FromRest(T.allOf)) : - IsUnion(T) ? Union(FromRest(T.anyOf)) : - IsObject(T) ? FromObject(T) : + IsComputed(type) ? FromComputed(type.target, type.parameters) : + IsRef(type) ? FromRef(type.$ref) : + IsIntersect(type) ? Intersect(FromRest(type.allOf)) : + IsUnion(type) ? Union(FromRest(type.anyOf)) : + IsObject(type) ? FromObject(type) : Object({}) ) as never } @@ -106,22 +132,24 @@ function PartialResolve(T: T): TPartial { // ------------------------------------------------------------------ // prettier-ignore export type TPartial = ( - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TFromObject> : + T extends TRecursive ? TRecursive> : + T extends TComputed ? TFromComputed : + T extends TRef ? TFromRef : + T extends TIntersect ? TIntersect> : + T extends TUnion ? TUnion> : + T extends TObject ? TFromObject> : TObject<{}> ) /** `[Json]` Constructs a type where all properties are optional */ -export function Partial(T: T, options?: SchemaOptions): TPartialFromMappedResult +export function Partial(type: MappedResult, options?: SchemaOptions): TPartialFromMappedResult /** `[Json]` Constructs a type where all properties are optional */ -export function Partial(T: T, options?: SchemaOptions): TPartial +export function Partial(type: Type, options?: SchemaOptions): TPartial /** `[Json]` Constructs a type where all properties are optional */ -export function Partial(T: TSchema, options?: SchemaOptions): any { - if (IsMappedResult(T)) { - return PartialFromMappedResult(T, options) +export function Partial(type: TSchema, options?: SchemaOptions): any { + if (IsMappedResult(type)) { + return PartialFromMappedResult(type, options) } else { // special: mapping types require overridable options - return CreateType({ ...PartialResolve(T), ...options }) + return CreateType({ ...PartialResolve(type), ...options }) } } diff --git a/src/type/pick/pick-from-mapped-key.ts b/src/type/pick/pick-from-mapped-key.ts index 062e1e527..86933aa58 100644 --- a/src/type/pick/pick-from-mapped-key.ts +++ b/src/type/pick/pick-from-mapped-key.ts @@ -36,77 +36,54 @@ import { Clone } from '../clone/value' // FromPropertyKey // ------------------------------------------------------------------ // prettier-ignore -type TFromPropertyKey< - T extends TSchema, - K extends PropertyKey, -> = { - [_ in K]: TPick - } +type TFromPropertyKey = { + [_ in Key]: TPick +} // prettier-ignore -function FromPropertyKey< - T extends TSchema, - K extends PropertyKey, ->(T: T, K: K, options?: SchemaOptions): TFromPropertyKey { +function FromPropertyKey(type: Type, key: Key, options?: SchemaOptions): TFromPropertyKey { return { - [K]: Pick(T, [K], Clone(options)) + [key]: Pick(type, [key], Clone(options)) } as never } // ------------------------------------------------------------------ // FromPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -type TFromPropertyKeys< - T extends TSchema, - K extends PropertyKey[], - Acc extends TProperties = {} -> = ( - K extends [infer LK extends PropertyKey, ...infer RK extends PropertyKey[]] - ? TFromPropertyKeys> - : Acc +type TFromPropertyKeys = ( + PropertyKeys extends [infer LeftKey extends PropertyKey, ...infer RightKeys extends PropertyKey[]] + ? TFromPropertyKeys> + : Result ) // prettier-ignore -function FromPropertyKeys< - T extends TSchema, - K extends PropertyKey[] ->(T: T, K: [...K], options?: SchemaOptions): TFromPropertyKeys { - return K.reduce((Acc, LK) => { - return { ...Acc, ...FromPropertyKey(T, LK, options) } +function FromPropertyKeys(type: Type, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromPropertyKeys { + return propertyKeys.reduce((result, leftKey) => { + return { ...result, ...FromPropertyKey(type, leftKey, options) } }, {} as TProperties) as never } // ------------------------------------------------------------------ // FromMappedKey // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedKey< - T extends TSchema, - K extends TMappedKey, -> = ( - TFromPropertyKeys +type TFromMappedKey = ( + TFromPropertyKeys ) // prettier-ignore -function FromMappedKey< - T extends TSchema, - K extends TMappedKey, ->(T: T, K: K, options?: SchemaOptions): TFromMappedKey { - return FromPropertyKeys(T, K.keys, options) as never +function FromMappedKey(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TFromMappedKey { + return FromPropertyKeys(type, mappedKey.keys, options) as never } // ------------------------------------------------------------------ // PickFromMappedKey // ------------------------------------------------------------------ // prettier-ignore -export type TPickFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TFromMappedKey +export type TPickFromMappedKey > = ( - TMappedResult

+ TMappedResult ) // prettier-ignore -export function PickFromMappedKey< - T extends TSchema, - K extends TMappedKey, - P extends TProperties = TFromMappedKey ->(T: T, K: K, options?: SchemaOptions): TMappedResult

{ - const P = FromMappedKey(T, K, options) - return MappedResult(P) as never +export function PickFromMappedKey +>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedResult { + const properties = FromMappedKey(type, mappedKey, options) + return MappedResult(properties) as never } diff --git a/src/type/pick/pick-from-mapped-result.ts b/src/type/pick/pick-from-mapped-result.ts index 3abf5ad17..7fa74f9c4 100644 --- a/src/type/pick/pick-from-mapped-result.ts +++ b/src/type/pick/pick-from-mapped-result.ts @@ -37,55 +37,41 @@ import { Clone } from '../clone/value' // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties< - P extends TProperties, - K extends PropertyKey[], -> = ( - { [K2 in keyof P]: TPick } +type TFromProperties = ( + { [K2 in keyof Properties]: TPick } ) // prettier-ignore -function FromProperties< - P extends TProperties, - K extends PropertyKey[], ->(P: P, K: [...K], options?: SchemaOptions): TFromProperties { - const Acc = {} as TProperties - for(const K2 of globalThis.Object.getOwnPropertyNames(P)) Acc[K2] = Pick(P[K2], K, Clone(options)) - return Acc as never +function FromProperties(properties: Properties, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromProperties { + const result = {} as TProperties + for(const K2 of globalThis.Object.getOwnPropertyNames(properties)) result[K2] = Pick(properties[K2], propertyKeys, Clone(options)) + return result as never } // ------------------------------------------------------------------ // FromMappedResult // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedResult< - R extends TMappedResult, - K extends PropertyKey[], -> = ( - Evaluate> +type TFromMappedResult = ( + Evaluate> ) // prettier-ignore -function FromMappedResult< - R extends TMappedResult, - K extends PropertyKey[] ->(R: R, K: [...K], options?: SchemaOptions): TFromMappedResult { - return FromProperties(R.properties, K, options) as never +function FromMappedResult(mappedResult: MappedResult, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TFromMappedResult { + return FromProperties(mappedResult.properties, propertyKeys, options) as never } // ------------------------------------------------------------------ // PickFromMappedResult // ------------------------------------------------------------------ // prettier-ignore -export type TPickFromMappedResult< - T extends TMappedResult, - K extends PropertyKey[], - P extends TProperties = TFromMappedResult +export type TPickFromMappedResult > = ( - Ensure> + Ensure> ) // prettier-ignore export function PickFromMappedResult< - R extends TMappedResult, - K extends PropertyKey[], - P extends TProperties = TFromMappedResult ->(R: R, K: [...K], options?: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(R, K, options) - return MappedResult(P) as never + MappedResult extends TMappedResult, + PropertyKeys extends PropertyKey[], + Properties extends TProperties = TFromMappedResult +>(mappedResult: MappedResult, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TMappedResult { + const properties = FromMappedResult(mappedResult, propertyKeys, options) + return MappedResult(properties) as never } diff --git a/src/type/pick/pick.ts b/src/type/pick/pick.ts index bde1e17f0..f9b988f46 100644 --- a/src/type/pick/pick.ts +++ b/src/type/pick/pick.ts @@ -31,59 +31,70 @@ import { Discard } from '../discard/discard' import type { TSchema, SchemaOptions } from '../schema/index' import type { TupleToUnion, Evaluate, Ensure } from '../helpers/index' import { type TRecursive } from '../recursive/index' -import { type TIntersect, Intersect } from '../intersect/index' -import { type TUnion, Union } from '../union/index' -import { type TObject, type TProperties, type TPropertyKey, Object } from '../object/index' -import type { TMappedKey, TMappedResult } from '../mapped/index' +import { Computed, type TComputed } from '../computed/index' +import { Intersect, type TIntersect } from '../intersect/index' +import { Literal, type TLiteral, type TLiteralValue } from '../literal/index' +import { Object, type TObject, type TProperties, type TPropertyKey } from '../object/index' +import { Union, type TUnion } from '../union/index' +import { type TMappedKey, type TMappedResult } from '../mapped/index' +import { type TRef } from '../ref/index' import { IndexPropertyKeys, type TIndexPropertyKeys } from '../indexed/index' -import { PickFromMappedKey, type TPickFromMappedKey } from './pick-from-mapped-key' -import { PickFromMappedResult, type TPickFromMappedResult } from './pick-from-mapped-result' import { TransformKind } from '../symbols/symbols' // ------------------------------------------------------------------ -// TypeGuard +// Guards +// ------------------------------------------------------------------ +import { IsMappedKey, IsMappedResult, IsIntersect, IsUnion, IsObject, IsSchema, IsLiteralValue, IsRef } from '../guard/kind' +import { IsArray as IsArrayValue } from 'src/value/guard' + +// ------------------------------------------------------------------ +// Infrastructure // ------------------------------------------------------------------ -import { IsMappedKey, IsMappedResult, IsIntersect, IsUnion, IsObject, IsSchema } from '../guard/kind' +import { PickFromMappedKey, type TPickFromMappedKey } from './pick-from-mapped-key' +import { PickFromMappedResult, type TPickFromMappedResult } from './pick-from-mapped-result' + // ------------------------------------------------------------------ // FromIntersect // ------------------------------------------------------------------ // prettier-ignore -type FromIntersect = - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? FromIntersect]> - : Acc -function FromIntersect(T: T, K: K) { - return T.map((T) => PickResolve(T, K)) as FromIntersect +type TFromIntersect = + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromIntersect]> + : Result +function FromIntersect(types: Types, propertyKeys: PropertyKeys): TFromIntersect { + return types.map((type) => PickResolve(type, propertyKeys)) as never } // ------------------------------------------------------------------ // FromUnion // ------------------------------------------------------------------ // prettier-ignore -type FromUnion = - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? FromUnion]> - : Acc +type TFromUnion = + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromUnion]> + : Result // prettier-ignore -function FromUnion(T: T, K: K) { - return T.map((T) => PickResolve(T, K)) as FromUnion +function FromUnion(types: Types, propertyKeys: PropertyKeys): TFromUnion { + return types.map((type) => PickResolve(type, propertyKeys)) as never } // ------------------------------------------------------------------ // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties> = Evaluate> +type TFromProperties> = ( + Evaluate> +) // prettier-ignore -function FromProperties(T: T, K: K): TFromProperties { - const Acc = {} as TProperties - for(const K2 of K) if(K2 in T) Acc[K2 as TPropertyKey] = T[K2 as keyof T] - return Acc as never +function FromProperties(properties: Properties, propertyKeys: PropertyKeys): TFromProperties { + const result = {} as TProperties + for(const K2 of propertyKeys) if(K2 in properties) result[K2 as TPropertyKey] = properties[K2 as keyof Properties] + return result as never } // ------------------------------------------------------------------ // FromObject // ------------------------------------------------------------------ // prettier-ignore -type TFromObject = Ensure +type TFromObject = Ensure )>> // prettier-ignore function FromObject(T: T, K: K): TFromObject { @@ -92,39 +103,86 @@ function FromObject(T: T, K: K): TFr return Object(properties, options) as never } // ------------------------------------------------------------------ -// PickResolve +// UnionFromPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -function PickResolve(T: T, K: [...K]): TPick { +type TUnionFromPropertyKeys = ( + PropertyKeys extends [infer Key extends PropertyKey, ...infer Rest extends PropertyKey[]] + ? Key extends TLiteralValue + ? TUnionFromPropertyKeys]> + : TUnionFromPropertyKeys + : TUnion +) +// prettier-ignore +function UnionFromPropertyKeys(propertyKeys: PropertyKeys): TUnionFromPropertyKeys { + const result = propertyKeys.reduce((result, key) => IsLiteralValue(key) ? [...result, Literal(key)]: result, [] as TLiteral[]) + return Union(result) as never +} +// ------------------------------------------------------------------ +// TPickResolve +// ------------------------------------------------------------------ +// prettier-ignore +export type TPickResolve = ( + Properties extends TRecursive ? TRecursive> : + Properties extends TIntersect ? TIntersect> : + Properties extends TUnion ? TUnion> : + Properties extends TObject ? TFromObject, PropertyKeys> : + TObject<{}> +) +// prettier-ignore +function PickResolve(properties: Properties, propertyKeys: [...PropertyKeys]): TPickResolve { return ( - IsIntersect(T) ? Intersect(FromIntersect(T.allOf, K)) : - IsUnion(T) ? Union(FromUnion(T.anyOf, K)) : - IsObject(T) ? FromObject(T, K) : + IsIntersect(properties) ? Intersect(FromIntersect(properties.allOf, propertyKeys)) : + IsUnion(properties) ? Union(FromUnion(properties.anyOf, propertyKeys)) : + IsObject(properties) ? FromObject(properties, propertyKeys) : Object({}) ) as never } +// ------------------------------------------------------------------ +// TPick +// +// This mapping logic is to overly complex because of the decision +// to use PropertyKey[] as the default selector. The PropertyKey[] +// did make TMapped types simpler to implement, but a non-TSchema +// selector makes supporting TComputed awkward as it requires +// generalization via TSchema. This type should be reimplemented +// in the next major revision to support TSchema as the primary +// selector. +// +// ------------------------------------------------------------------ +// prettier-ignore (do not export this type) +type TResolvePropertyKeys = Key extends TSchema ? TIndexPropertyKeys : Key +// prettier-ignore (do not export this type) +type TResolveTypeKey = Key extends PropertyKey[] ? TUnionFromPropertyKeys : Key // prettier-ignore -export type TPick = - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TFromObject, K> : - TObject<{}> - -/** `[Json]` Constructs a type whose keys are picked from the given type */ -export function Pick(T: T, K: [...K], options?: SchemaOptions): TPickFromMappedResult +export type TPick = ( + Type extends TMappedResult ? TPickFromMappedResult> : + Key extends TMappedKey ? TPickFromMappedKey : + [IsTypeRef, IsKeyRef] extends [true, true] ? TComputed<'Pick', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [false, true] ? TComputed<'Pick', [Type, TResolveTypeKey]> : + [IsTypeRef, IsKeyRef] extends [true, false] ? TComputed<'Pick', [Type, TResolveTypeKey]> : + TPickResolve> +) /** `[Json]` Constructs a type whose keys are picked from the given type */ -export function Pick(T: T, K: K, options?: SchemaOptions): TPickFromMappedKey +export function Pick(type: Type, key: readonly [...Key], options?: SchemaOptions): TPick /** `[Json]` Constructs a type whose keys are picked from the given type */ -export function Pick>(T: T, K: K, options?: SchemaOptions): TPick +export function Pick(type: Type, key: Key, options?: SchemaOptions): TPick /** `[Json]` Constructs a type whose keys are picked from the given type */ -export function Pick(T: T, K: readonly [...K], options?: SchemaOptions): TPick -export function Pick(T: TSchema, K: any, options?: SchemaOptions): any { - // mapped - if (IsMappedKey(K)) return PickFromMappedKey(T, K, options) - if (IsMappedResult(T)) return PickFromMappedResult(T, K, options) - // non-mapped - const I = IsSchema(K) ? IndexPropertyKeys(K) : (K as string[]) - // special: mapping types require overridable options - return CreateType({ ...PickResolve(T, I), ...options }) +// prettier-ignore +export function Pick(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(type) ? PickFromMappedResult(type, propertyKeys, options) : + IsMappedKey(key) ? PickFromMappedKey(type, key, options) : + (isTypeRef && isKeyRef) ? Computed('Pick', [type, typeKey], options) : + (!isTypeRef && isKeyRef) ? Computed('Pick', [type, typeKey], options) : + (isTypeRef && !isKeyRef) ? Computed('Pick', [type, typeKey], options) : + CreateType({ ...PickResolve(type, propertyKeys), ...options }) + ) as never } diff --git a/src/type/record/record.ts b/src/type/record/record.ts index e32ae7a26..34a87f74d 100644 --- a/src/type/record/record.ts +++ b/src/type/record/record.ts @@ -31,6 +31,7 @@ import type { TSchema } from '../schema/index' import type { Static } from '../static/index' import type { Evaluate, Ensure, Assert } from '../helpers/index' import { type TAny } from '../any/index' +import { Computed, type TComputed } from '../computed/index' import { Object, type TObject, type TProperties, type TAdditionalProperties, type ObjectOptions } from '../object/index' import { type TLiteral, type TLiteralValue } from '../literal/index' import { Never, type TNever } from '../never/index' @@ -40,6 +41,7 @@ import { type TString } from '../string/index' import { type TInteger } from '../integer/index' import { type TNumber } from '../number/index' import { type TEnum } from '../enum/index' +import { type TRef } from '../ref/index' import { IsTemplateLiteralFinite, TIsTemplateLiteralFinite, type TTemplateLiteral } from '../template-literal/index' import { PatternStringExact, PatternNumberExact, PatternNeverExact } from '../patterns/index' @@ -52,7 +54,8 @@ import { IsUndefined } from '../guard/value' // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsInteger, IsLiteral, IsAny, IsNever, IsNumber, IsString, IsRegExp, IsTemplateLiteral, IsUnion } from '../guard/kind' +import { IsInteger, IsLiteral, IsAny, IsNever, IsNumber, IsString, IsRegExp, IsTemplateLiteral, IsUnion, IsRef, IsComputed } from '../guard/kind' + // ------------------------------------------------------------------ // RecordCreateFromPattern // ------------------------------------------------------------------ @@ -218,34 +221,38 @@ export interface TRecord = - K extends TTemplateLiteral ? TFromTemplateLiteralKey : - K extends TEnum ? TFromEnumKey : // (Special: Ensure resolve Enum before Union) - K extends TUnion ? TFromUnionKey : - K extends TLiteral ? TFromLiteralKey : - K extends TInteger ? TFromIntegerKey : - K extends TNumber ? TFromNumberKey : - K extends TRegExp ? TFromRegExpKey : - K extends TString ? TFromStringKey : - K extends TAny ? TFromAnyKey : - K extends TNever ? TFromNeverKey : +export type TRecordOrObject = + Type extends TRef ? TComputed<'Record', [Key, Type]> : + Key extends TRef ? TComputed<'Record', [Key, Type]> : + Key extends TTemplateLiteral ? TFromTemplateLiteralKey : + Key extends TEnum ? TFromEnumKey : // (Special: Ensure resolve Enum before Union) + Key extends TUnion ? TFromUnionKey : + Key extends TLiteral ? TFromLiteralKey : + Key extends TInteger ? TFromIntegerKey : + Key extends TNumber ? TFromNumberKey : + Key extends TRegExp ? TFromRegExpKey : + Key extends TString ? TFromStringKey : + Key extends TAny ? TFromAnyKey : + Key extends TNever ? TFromNeverKey : TNever // ------------------------------------------------------------------ // TRecordOrObject // ------------------------------------------------------------------ /** `[Json]` Creates a Record type */ -export function Record(K: K, T: T, options: ObjectOptions = {}): TRecordOrObject { +export function Record(key: Key, type: Type, options: ObjectOptions = {}): TRecordOrObject { // prettier-ignore return ( - IsUnion(K) ? FromUnionKey(K.anyOf, T, options) : - IsTemplateLiteral(K) ? FromTemplateLiteralKey(K, T, options) : - IsLiteral(K) ? FromLiteralKey(K.const, T, options) : - IsInteger(K) ? FromIntegerKey(K, T, options) : - IsNumber(K) ? FromNumberKey(K, T, options) : - IsRegExp(K) ? FromRegExpKey(K, T, options) : - IsString(K) ? FromStringKey(K, T, options) : - IsAny(K) ? FromAnyKey(K, T, options) : - IsNever(K) ? FromNeverKey(K, T, options) : + IsRef(type) ? Computed('Record', [key, type]) : + IsRef(key) ? Computed('Record', [key, type]) : + IsUnion(key) ? FromUnionKey(key.anyOf, type, options) : + IsTemplateLiteral(key) ? FromTemplateLiteralKey(key, type, options) : + IsLiteral(key) ? FromLiteralKey(key.const, type, options) : + IsInteger(key) ? FromIntegerKey(key, type, options) : + IsNumber(key) ? FromNumberKey(key, type, options) : + IsRegExp(key) ? FromRegExpKey(key, type, options) : + IsString(key) ? FromStringKey(key, type, options) : + IsAny(key) ? FromAnyKey(key, type, options) : + IsNever(key) ? FromNeverKey(key, type, options) : Never(options) ) as never } diff --git a/src/type/required/required.ts b/src/type/required/required.ts index fab0632f2..7ae6a234d 100644 --- a/src/type/required/required.ts +++ b/src/type/required/required.ts @@ -31,12 +31,14 @@ import type { TSchema, SchemaOptions } from '../schema/index' import type { Evaluate, Ensure } from '../helpers/index' import type { TMappedResult } from '../mapped/index' import { type TReadonlyOptional } from '../readonly-optional/index' +import { type TComputed, Computed } from '../computed/index' import { type TOptional } from '../optional/index' import { type TReadonly } from '../readonly/index' import { type TRecursive } from '../recursive/index' +import { type TObject, type TProperties, Object } from '../object/index' import { type TIntersect, Intersect } from '../intersect/index' import { type TUnion, Union } from '../union/index' -import { type TObject, type TProperties, Object } from '../object/index' +import { type TRef, Ref } from '../ref/index' import { OptionalKind, TransformKind } from '../symbols/index' import { Discard } from '../discard/index' import { RequiredFromMappedResult, type TRequiredFromMappedResult } from './required-from-mapped-result' @@ -44,60 +46,84 @@ import { RequiredFromMappedResult, type TRequiredFromMappedResult } from './requ // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ -import { IsMappedResult, IsIntersect, IsUnion, IsObject } from '../guard/kind' +import { IsMappedResult, IsIntersect, IsUnion, IsObject, IsRef, IsComputed } from '../guard/kind' + // ------------------------------------------------------------------ -// FromRest +// FromComputed // ------------------------------------------------------------------ // prettier-ignore -type TFromRest = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest]> - : Acc -) +type TFromComputed = Ensure< + TComputed<'Required', [TComputed]> +> +// prettier-ignore +function FromComputed(target: Target, parameters: Parameters): TFromComputed { + return Computed('Required', [Computed(target, parameters)]) as never +} +// ------------------------------------------------------------------ +// FromRef +// ------------------------------------------------------------------ // prettier-ignore -function FromRest(T: [...T]) : TFromRest { - return T.map(L => RequiredResolve(L)) as never +type TFromRef = Ensure< + TComputed<'Required', [TRef]> +> +// prettier-ignore +function FromRef($ref: Ref): TFromRef { + return Computed('Required', [Ref($ref)]) as never } // ------------------------------------------------------------------ // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties = Evaluate<{ - [K in keyof T]: - T[K] extends (TReadonlyOptional) ? TReadonly : - T[K] extends (TReadonly) ? TReadonly : - T[K] extends (TOptional) ? S : - T[K] +type TFromProperties = Evaluate<{ + [K in keyof Properties]: + Properties[K] extends (TReadonlyOptional) ? TReadonly : + Properties[K] extends (TReadonly) ? TReadonly : + Properties[K] extends (TOptional) ? S : + Properties[K] }> // prettier-ignore -function FromProperties(T: T) { - const Acc = {} as TProperties - for(const K of globalThis.Object.getOwnPropertyNames(T)) Acc[K] = Discard(T[K], [OptionalKind]) as TSchema - return Acc as never +function FromProperties(properties: Properties) { + const requiredProperties = {} as TProperties + for(const K of globalThis.Object.getOwnPropertyNames(properties)) requiredProperties[K] = Discard(properties[K], [OptionalKind]) as TSchema + return requiredProperties as never } // ------------------------------------------------------------------ // FromObject // ------------------------------------------------------------------ // prettier-ignore -type TFromObject = Ensure = Ensure )>> // prettier-ignore -function FromObject(T: T): TFromObject { - const options = Discard(T, [TransformKind, '$id', 'required', 'properties']) - const properties = FromProperties(T['properties']) +function FromObject(type: Type): TFromObject { + const options = Discard(type, [TransformKind, '$id', 'required', 'properties']) + const properties = FromProperties(type['properties']) return Object(properties, options) as never } // ------------------------------------------------------------------ +// FromRest +// ------------------------------------------------------------------ +// prettier-ignore +type TFromRest = ( + Types extends [infer L extends TSchema, ...infer R extends TSchema[]] + ? TFromRest]> + : Result +) +// prettier-ignore +function FromRest(types: [...Types]) : TFromRest { + return types.map(type => RequiredResolve(type)) as never +} +// ------------------------------------------------------------------ // RequiredResolve // ------------------------------------------------------------------ - // prettier-ignore -function RequiredResolve(T: T): TRequired { +function RequiredResolve(type: Type): TRequired { return ( - IsIntersect(T) ? Intersect(FromRest(T.allOf)) : - IsUnion(T) ? Union(FromRest(T.anyOf)) : - IsObject(T) ? FromObject(T) : + IsComputed(type) ? FromComputed(type.target, type.parameters) : + IsRef(type) ? FromRef(type.$ref) : + IsIntersect(type) ? Intersect(FromRest(type.allOf)) : + IsUnion(type) ? Union(FromRest(type.anyOf)) : + IsObject(type) ? FromObject(type) : Object({}) ) as never } @@ -105,23 +131,25 @@ function RequiredResolve(T: T): TRequired { // TRequired // ------------------------------------------------------------------ // prettier-ignore -export type TRequired = ( - T extends TRecursive ? TRecursive> : - T extends TIntersect ? TIntersect> : - T extends TUnion ? TUnion> : - T extends TObject ? TFromObject> : +export type TRequired = ( + Type extends TRecursive ? TRecursive> : + Type extends TComputed ? TFromComputed : + Type extends TRef ? TFromRef : + Type extends TIntersect ? TIntersect> : + Type extends TUnion ? TUnion> : + Type extends TObject ? TFromObject> : TObject<{}> ) /** `[Json]` Constructs a type where all properties are required */ -export function Required(T: T, options?: SchemaOptions): TRequiredFromMappedResult +export function Required(type: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult /** `[Json]` Constructs a type where all properties are required */ -export function Required(T: T, options?: SchemaOptions): TRequired +export function Required(type: Type, options?: SchemaOptions): TRequired /** `[Json]` Constructs a type where all properties are required */ -export function Required(T: T, options?: SchemaOptions): never { - if (IsMappedResult(T)) { - return RequiredFromMappedResult(T, options) as never +export function Required(type: Type, options?: SchemaOptions): never { + if (IsMappedResult(type)) { + return RequiredFromMappedResult(type, options) as never } else { // special: mapping types require overridable options - return CreateType({ ...RequiredResolve(T), ...options }) as never + return CreateType({ ...RequiredResolve(type), ...options }) as never } } 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 7613dc3f4..acc91ce1f 100644 --- a/src/type/type/json.ts +++ b/src/type/type/json.ts @@ -39,7 +39,7 @@ import { Index, TIndex, type TIndexPropertyKeys, type TIndexFromMappedKey, type import { Integer, type IntegerOptions, type TInteger } from '../integer/index' import { Intersect, type IntersectOptions } from '../intersect/index' import { Capitalize, Uncapitalize, Lowercase, Uppercase, type TCapitalize, type TUncapitalize, type TLowercase, type TUppercase } from '../intrinsic/index' -import { KeyOf, type TKeyOf, type TKeyOfFromMappedResult } from '../keyof/index' +import { KeyOf, type TKeyOf } from '../keyof/index' import { Literal, type TLiteral, type TLiteralValue } from '../literal/index' import { Mapped, type TMappedFunction, type TMapped, type TMappedResult } from '../mapped/index' import { Never, type TNever } from '../never/index' @@ -49,10 +49,10 @@ import { type TMappedKey } from '../mapped/index' import { Module, TModule } from '../module/index' import { Number, type TNumber, type NumberOptions } from '../number/index' import { Object, type TObject, type TProperties, type ObjectOptions } from '../object/index' -import { Omit, type TOmit, type TOmitFromMappedKey, type TOmitFromMappedResult } from '../omit/index' +import { Omit, type TOmit } from '../omit/index' import { Optional, type TOptionalWithFlag, type TOptionalFromMappedResult } from '../optional/index' import { Partial, type TPartial, type TPartialFromMappedResult } from '../partial/index' -import { Pick, type TPick, type TPickFromMappedKey, type TPickFromMappedResult } from '../pick/index' +import { Pick, type TPick } from '../pick/index' import { Readonly, type TReadonlyWithFlag, type TReadonlyFromMappedResult } from '../readonly/index' import { ReadonlyOptional, type TReadonlyOptional } from '../readonly-optional/index' import { Record, type TRecordOrObject } from '../record/index' @@ -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,40 +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: T, options?: SchemaOptions): TKeyOfFromMappedResult - /** `[Json]` Creates a KeyOf type */ - public KeyOf(schema: T, options?: SchemaOptions): TKeyOf - /** `[Json]` Creates a KeyOf type */ - public KeyOf(schema: TSchema, options?: SchemaOptions): any { - return KeyOf(schema, options) + 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 @@ -216,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 { @@ -231,41 +227,33 @@ export class JsonTypeBuilder { public Object(properties: T, options?: ObjectOptions): TObject { return Object(properties, options) } + /** `[Json]` Constructs a type whose keys are picked from the given type */ + public Omit(type: Type, key: readonly [...Key], options?: SchemaOptions): TOmit + /** `[Json]` Constructs a type whose keys are picked from the given type */ + public Omit(type: Type, key: Key, options?: SchemaOptions): TOmit /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(T: T, K: [...K], options?: SchemaOptions): TOmitFromMappedResult - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(T: T, K: K, options?: SchemaOptions): TOmitFromMappedKey - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit>(T: T, K: K, options?: SchemaOptions): TOmit - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(T: T, K: readonly [...K], options?: SchemaOptions): TOmit - /** `[Json]` Constructs a type whose keys are omitted from the given type */ - public Omit(schema: TSchema, unresolved: any, options?: SchemaOptions): any { - return Omit(schema, unresolved, options) + public Omit(schema: TSchema, selector: any, options?: SchemaOptions): any { + return Omit(schema, selector, options) } /** `[Json]` Constructs a type where all properties are optional */ - public Partial(T: T, options?: SchemaOptions): TPartialFromMappedResult + public Partial(type: MappedResult, options?: SchemaOptions): TPartialFromMappedResult /** `[Json]` Constructs a type where all properties are optional */ - public Partial(schema: T, options?: SchemaOptions): TPartial + public Partial(type: Type, options?: SchemaOptions): TPartial /** `[Json]` Constructs a type where all properties are optional */ - public Partial(schema: TSchema, options?: SchemaOptions): any { - return Partial(schema, options) + public Partial(type: TSchema, options?: SchemaOptions): any { + return Partial(type, options) } /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(T: T, K: [...K], options?: SchemaOptions): TPickFromMappedResult - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(T: T, K: K, options?: SchemaOptions): TPickFromMappedKey - /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick>(T: T, K: K, options?: SchemaOptions): TPick + public Pick(type: Type, key: readonly [...Key], options?: SchemaOptions): TPick /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(T: T, K: readonly [...K], options?: SchemaOptions): TPick + public Pick(type: Type, key: Key, options?: SchemaOptions): TPick /** `[Json]` Constructs a type whose keys are picked from the given type */ - public Pick(schema: TSchema, unresolved: any, options?: SchemaOptions): any { - return Pick(schema, unresolved, options) + public Pick(type: any, key: any, options?: SchemaOptions): any { + 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 { @@ -276,44 +264,44 @@ export class JsonTypeBuilder { return Ref($ref, options) } /** `[Json]` Constructs a type where all properties are required */ - public Required(T: T, options?: SchemaOptions): TRequiredFromMappedResult + public Required(type: MappedResult, options?: SchemaOptions): TRequiredFromMappedResult /** `[Json]` Constructs a type where all properties are required */ - public Required(schema: T, options?: SchemaOptions): TRequired + public Required(type: Type, options?: SchemaOptions): TRequired /** `[Json]` Constructs a type where all properties are required */ - public Required(schema: TSchema, options?: SchemaOptions): any { - return Required(schema, options) + public Required(type: TSchema, options?: SchemaOptions): any { + 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 } diff --git a/src/value/cast/cast.ts b/src/value/cast/cast.ts index a6f9d9891..bdcb7b8c0 100644 --- a/src/value/cast/cast.ts +++ b/src/value/cast/cast.ts @@ -136,7 +136,7 @@ function FromConstructor(schema: TConstructor, references: TSchema[], value: any } function FromImport(schema: TImport, references: TSchema[], value: unknown): boolean { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: any): any { diff --git a/src/value/check/check.ts b/src/value/check/check.ts index b1af0dd26..7ac4e1e82 100644 --- a/src/value/check/check.ts +++ b/src/value/check/check.ts @@ -75,9 +75,9 @@ import type { TVoid } from '../../type/void/index' // ------------------------------------------------------------------ import { IsArray, IsUint8Array, IsDate, IsPromise, IsFunction, IsAsyncIterator, IsIterator, IsBoolean, IsNumber, IsBigInt, IsString, IsSymbol, IsInteger, IsNull, IsUndefined } from '../guard/index' // ------------------------------------------------------------------ -// TypeGuard +// KindGuard // ------------------------------------------------------------------ -import { IsSchema } from '../../type/guard/type' +import { IsSchema } from '../../type/guard/kind' // ------------------------------------------------------------------ // Errors // ------------------------------------------------------------------ @@ -188,7 +188,7 @@ function FromFunction(schema: TFunction, references: TSchema[], value: any): boo } function FromImport(schema: TImport, references: TSchema[], value: any): boolean { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions], value) } function FromInteger(schema: TInteger, references: TSchema[], value: any): boolean { diff --git a/src/value/clean/clean.ts b/src/value/clean/clean.ts index 341cf025e..1e7df9f3b 100644 --- a/src/value/clean/clean.ts +++ b/src/value/clean/clean.ts @@ -77,7 +77,7 @@ function FromArray(schema: TArray, references: TSchema[], value: unknown): any { } function FromImport(schema: TImport, references: TSchema[], value: unknown): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown): any { diff --git a/src/value/convert/convert.ts b/src/value/convert/convert.ts index 1cfaa1081..bacae2bad 100644 --- a/src/value/convert/convert.ts +++ b/src/value/convert/convert.ts @@ -185,7 +185,7 @@ function FromDate(schema: TDate, references: TSchema[], value: any): unknown { } function FromImport(schema: TImport, references: TSchema[], value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions], value) } function FromInteger(schema: TInteger, references: TSchema[], value: any): unknown { diff --git a/src/value/create/create.ts b/src/value/create/create.ts index 478aab130..00a0c0c17 100644 --- a/src/value/create/create.ts +++ b/src/value/create/create.ts @@ -170,7 +170,7 @@ function FromFunction(schema: TFunction, references: TSchema[]): any { } function FromImport(schema: TImport, references: TSchema[]): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions]) } function FromInteger(schema: TInteger, references: TSchema[]): any { diff --git a/src/value/default/default.ts b/src/value/default/default.ts index 30ddbc95b..3e3790478 100644 --- a/src/value/default/default.ts +++ b/src/value/default/default.ts @@ -81,7 +81,7 @@ function FromDate(schema: TArray, references: TSchema[], value: unknown): any { } function FromImport(schema: TImport, references: TSchema[], value: unknown): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown): any { diff --git a/src/value/transform/decode.ts b/src/value/transform/decode.ts index 2498058b1..8bb957b09 100644 --- a/src/value/transform/decode.ts +++ b/src/value/transform/decode.ts @@ -51,9 +51,9 @@ import type { TUnion } from '../../type/union/index' // ------------------------------------------------------------------ import { HasPropertyKey, IsObject, IsArray, IsValueType, IsUndefined as IsUndefinedValue } from '../guard/index' // ------------------------------------------------------------------ -// TypeGuard +// KindGuard // ------------------------------------------------------------------ -import { IsTransform, IsSchema, IsUndefined } from '../../type/guard/type' +import { IsTransform, IsSchema, IsUndefined } from '../../type/guard/kind' // ------------------------------------------------------------------ // Errors // ------------------------------------------------------------------ @@ -119,7 +119,7 @@ function FromIntersect(schema: TIntersect, references: TSchema[], path: string, // prettier-ignore function FromImport(schema: TImport, references: TSchema[], path: string, value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema const transform = schema[TransformKind as never] // Note: we need to re-spec the target as TSchema + [TransformKind] const transformTarget = { [TransformKind]: transform, ...target } as TSchema diff --git a/src/value/transform/encode.ts b/src/value/transform/encode.ts index 1f033dc79..3be3ba671 100644 --- a/src/value/transform/encode.ts +++ b/src/value/transform/encode.ts @@ -51,9 +51,9 @@ import type { TUnion } from '../../type/union/index' // ------------------------------------------------------------------ import { HasPropertyKey, IsObject, IsArray, IsValueType, IsUndefined as IsUndefinedValue } from '../guard/index' // ------------------------------------------------------------------ -// TypeGuard +// KindGuard // ------------------------------------------------------------------ -import { IsTransform, IsSchema, IsUndefined } from '../../type/guard/type' +import { IsTransform, IsSchema, IsUndefined } from '../../type/guard/kind' // ------------------------------------------------------------------ // Errors // ------------------------------------------------------------------ @@ -99,7 +99,7 @@ function FromArray(schema: TArray, references: TSchema[], path: string, value: a // prettier-ignore function FromImport(schema: TImport, references: TSchema[], path: string, value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref] as TSchema + const target = schema.$defs[schema.$ref as never] as TSchema const transform = schema[TransformKind as never] // Note: we need to re-spec the target as TSchema + [TransformKind] const transformTarget = { [TransformKind]: transform, ...target } as TSchema diff --git a/src/value/transform/has.ts b/src/value/transform/has.ts index 7481d86a1..5a0d785c3 100644 --- a/src/value/transform/has.ts +++ b/src/value/transform/has.ts @@ -46,9 +46,9 @@ import type { TTuple } from '../../type/tuple/index' import type { TUnion } from '../../type/union/index' // ------------------------------------------------------------------ -// TypeGuard +// KindGuard // ------------------------------------------------------------------ -import { IsTransform, IsSchema } from '../../type/guard/type' +import { IsTransform, IsSchema } from '../../type/guard/kind' // ------------------------------------------------------------------ // ValueGuard // ------------------------------------------------------------------ diff --git a/test/runtime/type/guard/kind/import.ts b/test/runtime/type/guard/kind/import.ts index ee430ad6d..5feb06523 100644 --- a/test/runtime/type/guard/kind/import.ts +++ b/test/runtime/type/guard/kind/import.ts @@ -2,14 +2,154 @@ import { KindGuard } from '@sinclair/typebox' import { Type } from '@sinclair/typebox' import { Assert } from '../../../assert/index' -describe('guard/type/TImport', () => { +describe('guard/kind/TImport', () => { it('Should guard for TImport', () => { - const M = Type.Module({ + const Module = Type.Module({ A: Type.String(), }) - const I = M.Import('A') - const N = I.$defs[I.$ref] - Assert.IsTrue(KindGuard.IsImport(I)) + const A = Module.Import('A') + const N = A.$defs[A.$ref] + Assert.IsTrue(KindGuard.IsImport(A)) Assert.IsTrue(KindGuard.IsString(N)) }) + // ---------------------------------------------------------------- + // Computed: Awaited + // ---------------------------------------------------------------- + it('Should compute for Awaited', () => { + const Module = Type.Module({ + T: Type.Promise(Type.String()), + R: Type.Awaited(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsString(T.$defs['R'])) + }) + // ---------------------------------------------------------------- + // Computed: Index (Note: Pending Reimplementation of Index) + // ---------------------------------------------------------------- + it('Should compute for Index 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + I: Type.Literal('x'), + R: Type.Index(Type.Ref('T'), Type.Ref('I')) as never, // fail + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'])) + }) + // ---------------------------------------------------------------- + // Computed: Omit + // ---------------------------------------------------------------- + it('Should compute for Omit 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + R: Type.Omit(Type.Ref('T'), Type.Literal('x')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.y)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.x === undefined) + }) + it('Should compute for Omit 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + K: Type.Literal('x'), + R: Type.Omit(Type.Ref('T'), Type.Ref('K')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.y)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.x === undefined) + }) + // ---------------------------------------------------------------- + // Computed: Partial + // ---------------------------------------------------------------- + it('Should compute for Partial', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number() }), + R: Type.Partial(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsTrue(KindGuard.IsOptional(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: Pick + // ---------------------------------------------------------------- + it('Should compute for Pick 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + R: Type.Pick(Type.Ref('T'), Type.Literal('x')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.y === undefined) + }) + it('Should compute for Pick 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + K: Type.Literal('x'), + R: Type.Pick(Type.Ref('T'), Type.Ref('K')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.y === undefined) + }) + // ---------------------------------------------------------------- + // Computed: Record + // ---------------------------------------------------------------- + it('Should compute for Record 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + R: Type.Record(Type.String(), Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsRecord(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].patternProperties['^(.*)$'].properties.x)) + Assert.IsTrue(KindGuard.IsString(T.$defs['R'].patternProperties['^(.*)$'].properties.y)) + }) + it('Should compute for Record 2', () => { + const Module = Type.Module({ + T: Type.Number(), + K: Type.Union([Type.Literal('x'), Type.Literal('y')]), + R: Type.Record(Type.Ref('K'), Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: Required + // ---------------------------------------------------------------- + it('Should compute for Required', () => { + const Module = Type.Module({ + T: Type.Partial(Type.Object({ x: Type.Number() })), + R: Type.Required(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsFalse(KindGuard.IsOptional(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: KeyOf + // ---------------------------------------------------------------- + it('Should compute for KeyOf', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + R: Type.KeyOf(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(KindGuard.IsUnion(T.$defs['R'])) + Assert.IsTrue(KindGuard.IsLiteral(T.$defs['R'].anyOf[0])) + Assert.IsTrue(KindGuard.IsLiteral(T.$defs['R'].anyOf[1])) + Assert.IsTrue(T.$defs['R'].anyOf[0].const === 'x') + Assert.IsTrue(T.$defs['R'].anyOf[1].const === 'y') + }) }) diff --git a/test/runtime/type/guard/type/import.ts b/test/runtime/type/guard/type/import.ts index fdce650c6..f38124320 100644 --- a/test/runtime/type/guard/type/import.ts +++ b/test/runtime/type/guard/type/import.ts @@ -4,12 +4,152 @@ import { Assert } from '../../../assert/index' describe('guard/type/TImport', () => { it('Should guard for TImport', () => { - const M = Type.Module({ + const Module = Type.Module({ A: Type.String(), }) - const I = M.Import('A') - const N = I.$defs[I.$ref] - Assert.IsTrue(TypeGuard.IsImport(I)) + const A = Module.Import('A') + const N = A.$defs[A.$ref] + Assert.IsTrue(TypeGuard.IsImport(A)) Assert.IsTrue(TypeGuard.IsString(N)) }) + // ---------------------------------------------------------------- + // Computed: Awaited + // ---------------------------------------------------------------- + it('Should compute for Awaited', () => { + const Module = Type.Module({ + T: Type.Promise(Type.String()), + R: Type.Awaited(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsString(T.$defs['R'])) + }) + // ---------------------------------------------------------------- + // Computed: Index (Note: Pending Reimplementation of Index) + // ---------------------------------------------------------------- + it('Should compute for Index 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + I: Type.Literal('x'), + R: Type.Index(Type.Ref('T'), Type.Ref('I')) as never, // fail + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'])) + }) + // ---------------------------------------------------------------- + // Computed: Omit + // ---------------------------------------------------------------- + it('Should compute for Omit 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + R: Type.Omit(Type.Ref('T'), Type.Literal('x')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.y)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.x === undefined) + }) + it('Should compute for Omit 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + K: Type.Literal('x'), + R: Type.Omit(Type.Ref('T'), Type.Ref('K')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.y)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.x === undefined) + }) + // ---------------------------------------------------------------- + // Computed: Partial + // ---------------------------------------------------------------- + it('Should compute for Partial', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number() }), + R: Type.Partial(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsTrue(TypeGuard.IsOptional(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: Pick + // ---------------------------------------------------------------- + it('Should compute for Pick 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + R: Type.Pick(Type.Ref('T'), Type.Literal('x')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.y === undefined) + }) + it('Should compute for Pick 2', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.Number() }), + K: Type.Literal('x'), + R: Type.Pick(Type.Ref('T'), Type.Ref('K')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + // @ts-ignore + Assert.IsTrue(T.$defs['R'].properties.y === undefined) + }) + // ---------------------------------------------------------------- + // Computed: Record + // ---------------------------------------------------------------- + it('Should compute for Record 1', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + R: Type.Record(Type.String(), Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsRecord(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].patternProperties['^(.*)$'].properties.x)) + Assert.IsTrue(TypeGuard.IsString(T.$defs['R'].patternProperties['^(.*)$'].properties.y)) + }) + it('Should compute for Record 2', () => { + const Module = Type.Module({ + T: Type.Number(), + K: Type.Union([Type.Literal('x'), Type.Literal('y')]), + R: Type.Record(Type.Ref('K'), Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: Required + // ---------------------------------------------------------------- + it('Should compute for Required', () => { + const Module = Type.Module({ + T: Type.Partial(Type.Object({ x: Type.Number() })), + R: Type.Required(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsObject(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsNumber(T.$defs['R'].properties.x)) + Assert.IsFalse(TypeGuard.IsOptional(T.$defs['R'].properties.x)) + }) + // ---------------------------------------------------------------- + // Computed: KeyOf + // ---------------------------------------------------------------- + it('Should compute for KeyOf', () => { + const Module = Type.Module({ + T: Type.Object({ x: Type.Number(), y: Type.String() }), + R: Type.KeyOf(Type.Ref('T')), + }) + const T = Module.Import('R') + Assert.IsTrue(TypeGuard.IsUnion(T.$defs['R'])) + Assert.IsTrue(TypeGuard.IsLiteral(T.$defs['R'].anyOf[0])) + Assert.IsTrue(TypeGuard.IsLiteral(T.$defs['R'].anyOf[1])) + Assert.IsTrue(T.$defs['R'].anyOf[0].const === 'x') + Assert.IsTrue(T.$defs['R'].anyOf[1].const === 'y') + }) }) diff --git a/test/static/pick.ts b/test/static/pick.ts index de29ba4bb..895cdefac 100644 --- a/test/static/pick.ts +++ b/test/static/pick.ts @@ -27,7 +27,7 @@ import { Type, Static } from '@sinclair/typebox' const keys = ['A', 'B'] as const - const T = Type.Pick(A, keys) + const T = Type.Pick(A, ['A', 'B']) type T = Static From 72f2adcd2b5662877ae151b46a058df436089c71 Mon Sep 17 00:00:00 2001 From: sinclair Date: Sun, 17 Nov 2024 05:34:28 +0900 Subject: [PATCH 2/5] ChangeLog --- changelog/0.34.0.md | 4 ++++ readme.md | 41 ++++++++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 17 deletions(-) diff --git a/changelog/0.34.0.md b/changelog/0.34.0.md index fdc9a75ff..e9f754629 100644 --- a/changelog/0.34.0.md +++ b/changelog/0.34.0.md @@ -1,3 +1,7 @@ +### 0.34.0 +- [Revision 0.34.1](https://github.com/sinclairzx81/typebox/pull/1080) + - Implement Computed Type Deref in Modules + ## [0.34.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.34.0) ## Overview diff --git a/readme.md b/readme.md index 10b29574c..0d3ec1cb1 100644 --- a/readme.md +++ b/readme.md @@ -1074,25 +1074,32 @@ const T = Type.Object({ // const T: TObject<{ ### Module -Syntax Types also support Module parsing. This can provide a more terse syntax for creating Module definitions, but comes with an inference performance cost. Module parsing supports interface and type alias definitions. Generics types are currently unsupported. Consider the following which defines a explicit Module on the left, and the parsed Module on the right. +Syntax Types also support Module parsing. This can provide a more terse syntax for creating Module definitions, but comes with an inference performance cost. Module parsing supports interface and type alias definitions. Generics types are currently unsupported. ```typescript -const Module = Type.Module({ // const Module = Parse(`module { - // - User: Type.Object({ // export interface User { - id: Type.String(), // id: string - name: Type.String(), // name: string - email: Type.String(), // email: string - }), // } - // - PartialUser: Type.Intersect([ // export type PartialUser = ( - Type.Pick(Type.Ref('User'), ['id']), // Pick & - Type.Partial( // Partial> - Type.Omit(Type.Ref('User'), ['id']) // ) - ), // - ]) // - // -}) // }`) +const Module = Parse(`module { + + export interface User { + id: string + name: string + email: string + } + + export type PartialUser = ( + Pick & + Partial> + ) + +}`) + +const PartialUser = Module.Import('PartialUser') // TImport<{...}, 'PartialUser'> + +type PartialUser = Static // type PartialUser = { + // id: string, + // } & { + // name?: string, + // email?: string, + // } ``` From 5241fc633054e2c9803558fecfa3dff14a3cefee Mon Sep 17 00:00:00 2001 From: sinclair Date: Sun, 17 Nov 2024 05:40:11 +0900 Subject: [PATCH 3/5] Unused Import | Type Rename --- src/type/module/infer.ts | 4 ++-- src/type/module/module.ts | 7 +++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/type/module/infer.ts b/src/type/module/infer.ts index ff37ce0a7..082b7f733 100644 --- a/src/type/module/infer.ts +++ b/src/type/module/infer.ts @@ -151,11 +151,11 @@ type TInfer = ( Static ) // ------------------------------------------------------------------ -// InferImport +// InferFromModuleKey // ------------------------------------------------------------------ /** Inference Path for Imports. This type is used to compute TImport `static` */ // prettier-ignore -export type TInferType = ( +export type TInferFromModuleKey = ( Key extends keyof ModuleProperties ? TInfer : never diff --git a/src/type/module/module.ts b/src/type/module/module.ts index cf5cfd8ce..a4c2544e9 100644 --- a/src/type/module/module.ts +++ b/src/type/module/module.ts @@ -35,9 +35,8 @@ import { Static } from '../static/index' // ------------------------------------------------------------------ // Module Infrastructure Types // ------------------------------------------------------------------ -import { type TComputeType } from './compute' import { ComputeModuleProperties, TComputeModuleProperties } from './compute' -import { TInferType } from './infer' +import { TInferFromModuleKey } from './infer' // ------------------------------------------------------------------ // Definitions @@ -52,8 +51,8 @@ export interface TDefinitions extends TSch // prettier-ignore export interface TImport extends TSchema { [Kind]: 'Import' - static: TInferType - $defs: TComputeModuleProperties + static: TInferFromModuleKey + $defs: ModuleProperties $ref: Key } // ------------------------------------------------------------------ From 83979c4703a755168f752ac844c7e1e896ae5344 Mon Sep 17 00:00:00 2001 From: sinclair Date: Sun, 17 Nov 2024 05:44:48 +0900 Subject: [PATCH 4/5] Revert Never Assertion on Definition Key Indexer --- src/compiler/compiler.ts | 2 +- src/errors/errors.ts | 2 +- src/value/cast/cast.ts | 2 +- src/value/check/check.ts | 2 +- src/value/clean/clean.ts | 2 +- src/value/convert/convert.ts | 2 +- src/value/create/create.ts | 2 +- src/value/default/default.ts | 2 +- src/value/transform/decode.ts | 2 +- src/value/transform/encode.ts | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/compiler/compiler.ts b/src/compiler/compiler.ts index 01ab4dcf6..6e438702b 100644 --- a/src/compiler/compiler.ts +++ b/src/compiler/compiler.ts @@ -291,7 +291,7 @@ export namespace TypeCompiler { } function* FromImport(schema: TImport, references: TSchema[], value: string): IterableIterator { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema yield* Visit(target, [...references, ...definitions], value) } function* FromInteger(schema: TInteger, references: TSchema[], value: string): IterableIterator { diff --git a/src/errors/errors.ts b/src/errors/errors.ts index b7ac37f4c..9bb1f6cd1 100644 --- a/src/errors/errors.ts +++ b/src/errors/errors.ts @@ -305,7 +305,7 @@ function* FromFunction(schema: TFunction, references: TSchema[], path: string, v } function* FromImport(schema: TImport, references: TSchema[], path: string, value: any): IterableIterator { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema yield* Visit(target, [...references, ...definitions], path, value) } function* FromInteger(schema: TInteger, references: TSchema[], path: string, value: any): IterableIterator { diff --git a/src/value/cast/cast.ts b/src/value/cast/cast.ts index bdcb7b8c0..a6f9d9891 100644 --- a/src/value/cast/cast.ts +++ b/src/value/cast/cast.ts @@ -136,7 +136,7 @@ function FromConstructor(schema: TConstructor, references: TSchema[], value: any } function FromImport(schema: TImport, references: TSchema[], value: unknown): boolean { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: any): any { diff --git a/src/value/check/check.ts b/src/value/check/check.ts index 7ac4e1e82..c5244e22a 100644 --- a/src/value/check/check.ts +++ b/src/value/check/check.ts @@ -188,7 +188,7 @@ function FromFunction(schema: TFunction, references: TSchema[], value: any): boo } function FromImport(schema: TImport, references: TSchema[], value: any): boolean { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions], value) } function FromInteger(schema: TInteger, references: TSchema[], value: any): boolean { diff --git a/src/value/clean/clean.ts b/src/value/clean/clean.ts index 1e7df9f3b..341cf025e 100644 --- a/src/value/clean/clean.ts +++ b/src/value/clean/clean.ts @@ -77,7 +77,7 @@ function FromArray(schema: TArray, references: TSchema[], value: unknown): any { } function FromImport(schema: TImport, references: TSchema[], value: unknown): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown): any { diff --git a/src/value/convert/convert.ts b/src/value/convert/convert.ts index bacae2bad..1cfaa1081 100644 --- a/src/value/convert/convert.ts +++ b/src/value/convert/convert.ts @@ -185,7 +185,7 @@ function FromDate(schema: TDate, references: TSchema[], value: any): unknown { } function FromImport(schema: TImport, references: TSchema[], value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions], value) } function FromInteger(schema: TInteger, references: TSchema[], value: any): unknown { diff --git a/src/value/create/create.ts b/src/value/create/create.ts index 00a0c0c17..478aab130 100644 --- a/src/value/create/create.ts +++ b/src/value/create/create.ts @@ -170,7 +170,7 @@ function FromFunction(schema: TFunction, references: TSchema[]): any { } function FromImport(schema: TImport, references: TSchema[]): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions]) } function FromInteger(schema: TInteger, references: TSchema[]): any { diff --git a/src/value/default/default.ts b/src/value/default/default.ts index 3e3790478..30ddbc95b 100644 --- a/src/value/default/default.ts +++ b/src/value/default/default.ts @@ -81,7 +81,7 @@ function FromDate(schema: TArray, references: TSchema[], value: unknown): any { } function FromImport(schema: TImport, references: TSchema[], value: unknown): any { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema return Visit(target, [...references, ...definitions], value) } function FromIntersect(schema: TIntersect, references: TSchema[], value: unknown): any { diff --git a/src/value/transform/decode.ts b/src/value/transform/decode.ts index 8bb957b09..013b0abd1 100644 --- a/src/value/transform/decode.ts +++ b/src/value/transform/decode.ts @@ -119,7 +119,7 @@ function FromIntersect(schema: TIntersect, references: TSchema[], path: string, // prettier-ignore function FromImport(schema: TImport, references: TSchema[], path: string, value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema const transform = schema[TransformKind as never] // Note: we need to re-spec the target as TSchema + [TransformKind] const transformTarget = { [TransformKind]: transform, ...target } as TSchema diff --git a/src/value/transform/encode.ts b/src/value/transform/encode.ts index 3be3ba671..3ac8c54c8 100644 --- a/src/value/transform/encode.ts +++ b/src/value/transform/encode.ts @@ -99,7 +99,7 @@ function FromArray(schema: TArray, references: TSchema[], path: string, value: a // prettier-ignore function FromImport(schema: TImport, references: TSchema[], path: string, value: unknown): unknown { const definitions = globalThis.Object.values(schema.$defs) as TSchema[] - const target = schema.$defs[schema.$ref as never] as TSchema + const target = schema.$defs[schema.$ref] as TSchema const transform = schema[TransformKind as never] // Note: we need to re-spec the target as TSchema + [TransformKind] const transformTarget = { [TransformKind]: transform, ...target } as TSchema From ff615abb1ee5d5a790a0df9bc51dfa4477ae097d Mon Sep 17 00:00:00 2001 From: sinclair Date: Sun, 17 Nov 2024 05:49:09 +0900 Subject: [PATCH 5/5] Format on Index Mapped Result --- .../indexed/indexed-from-mapped-result.ts | 44 ++++++------------- 1 file changed, 14 insertions(+), 30 deletions(-) diff --git a/src/type/indexed/indexed-from-mapped-result.ts b/src/type/indexed/indexed-from-mapped-result.ts index 136e7a1ba..e2b2b007c 100644 --- a/src/type/indexed/indexed-from-mapped-result.ts +++ b/src/type/indexed/indexed-from-mapped-result.ts @@ -36,17 +36,11 @@ import { Index, type TIndex } from './index' // FromProperties // ------------------------------------------------------------------ // prettier-ignore -type TFromProperties< - Type extends TSchema, - Properties extends TProperties -> = ( +type TFromProperties = ( { [K2 in keyof Properties]: TIndex> } ) // prettier-ignore -function FromProperties< - Type extends TSchema, - Properties extends TProperties ->(type: Type, properties: Properties, options?: SchemaOptions): TFromProperties { +function FromProperties(type: Type, properties: Properties, options?: SchemaOptions): TFromProperties { const result = {} as Record for(const K2 of Object.getOwnPropertyNames(properties)) { const keys = IndexPropertyKeys(properties[K2]) @@ -58,36 +52,26 @@ function FromProperties< // FromMappedResult // ------------------------------------------------------------------ // prettier-ignore -type TFromMappedResult< - T extends TSchema, - R extends TMappedResult -> = ( - TFromProperties +type TFromMappedResult = ( + TFromProperties ) // prettier-ignore -function FromMappedResult< - T extends TSchema, - R extends TMappedResult ->(T: T, R: R, options?: SchemaOptions): TFromMappedResult { - return FromProperties(T, R.properties, options) as never +function FromMappedResult(type: Type, mappedResult: MappedResult, options?: SchemaOptions): TFromMappedResult { + return FromProperties(type, mappedResult.properties, options) as never } // ------------------------------------------------------------------ // TIndexFromMappedResult // ------------------------------------------------------------------ // prettier-ignore -export type TIndexFromMappedResult< - T extends TSchema, - R extends TMappedResult, - P extends TProperties = TFromMappedResult +export type TIndexFromMappedResult > = ( - TMappedResult

+ TMappedResult ) // prettier-ignore -export function IndexFromMappedResult< - T extends TSchema, - R extends TMappedResult, - P extends TProperties = TFromMappedResult ->(T: T, R: R, options?: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(T, R, options) - return MappedResult(P) as never +export function IndexFromMappedResult +>(type: Type, mappedResult: MappedResult, options?: SchemaOptions): TMappedResult { + const properties = FromMappedResult(type, mappedResult, options) + return MappedResult(properties) as never }