From 3b3781d6eaf5be83baf953d9a7814a64f789f74c Mon Sep 17 00:00:00 2001 From: sinclair <haydn.developer@gmail.com> Date: Wed, 4 Dec 2024 16:19:15 +0900 Subject: [PATCH] Use Overloads for Index Signature --- src/type/indexed/indexed-from-mapped-key.ts | 11 +- .../indexed/indexed-from-mapped-result.ts | 3 +- src/type/indexed/indexed-property-keys.ts | 28 ++- src/type/indexed/indexed.ts | 218 ++++++++---------- src/type/module/compute.ts | 18 +- src/type/type/json.ts | 16 +- 6 files changed, 137 insertions(+), 157 deletions(-) diff --git a/src/type/indexed/indexed-from-mapped-key.ts b/src/type/indexed/indexed-from-mapped-key.ts index b66cf511..a523032f 100644 --- a/src/type/indexed/indexed-from-mapped-key.ts +++ b/src/type/indexed/indexed-from-mapped-key.ts @@ -41,8 +41,7 @@ type TMappedIndexPropertyKey<Type extends TSchema, Key extends PropertyKey> = { [_ in Key]: TIndex<Type, [Key]> } // prettier-ignore -function MappedIndexPropertyKey<Type extends TSchema, Key extends PropertyKey ->(type: Type, key: Key, options?: SchemaOptions): TMappedIndexPropertyKey<Type, Key> { +function MappedIndexPropertyKey<Type extends TSchema, Key extends PropertyKey>(type: Type, key: Key, options?: SchemaOptions): TMappedIndexPropertyKey<Type, Key> { return { [key]: Index(type, [key], Clone(options)) } as never } // ------------------------------------------------------------------ @@ -55,7 +54,10 @@ type TMappedIndexPropertyKeys<Type extends TSchema, PropertyKeys extends Propert : Result ) // prettier-ignore -function MappedIndexPropertyKeys<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TMappedIndexPropertyKeys<Type, PropertyKeys> { +function MappedIndexPropertyKeys< + Type extends TSchema, + PropertyKeys extends PropertyKey[] +>(type: Type, propertyKeys: [...PropertyKeys], options?: SchemaOptions): TMappedIndexPropertyKeys<Type, PropertyKeys> { return propertyKeys.reduce((result, left) => { return { ...result, ...MappedIndexPropertyKey(type, left, options) } }, {} as TProperties) as never @@ -68,7 +70,8 @@ type TMappedIndexProperties<Type extends TSchema, MappedKey extends TMappedKey> TMappedIndexPropertyKeys<Type, MappedKey['keys']> > // prettier-ignore -function MappedIndexProperties<Type extends TSchema, MappedKey extends TMappedKey>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedIndexProperties<Type, MappedKey> { +function MappedIndexProperties<Type extends TSchema, MappedKey extends TMappedKey +>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TMappedIndexProperties<Type, MappedKey> { return MappedIndexPropertyKeys(type, mappedKey.keys, options) as never } // ------------------------------------------------------------------ diff --git a/src/type/indexed/indexed-from-mapped-result.ts b/src/type/indexed/indexed-from-mapped-result.ts index e2b2b007..20049364 100644 --- a/src/type/indexed/indexed-from-mapped-result.ts +++ b/src/type/indexed/indexed-from-mapped-result.ts @@ -43,8 +43,7 @@ type TFromProperties<Type extends TSchema, Properties extends TProperties> = ( function FromProperties<Type extends TSchema, Properties extends TProperties>(type: Type, properties: Properties, options?: SchemaOptions): TFromProperties<Type, Properties> { const result = {} as Record<PropertyKey, TSchema> for(const K2 of Object.getOwnPropertyNames(properties)) { - const keys = IndexPropertyKeys(properties[K2]) - result[K2] = Index(type, keys, options) as never + result[K2] = Index(type, IndexPropertyKeys(properties[K2]), options) } return result as never } diff --git a/src/type/indexed/indexed-property-keys.ts b/src/type/indexed/indexed-property-keys.ts index ad73541e..c939da23 100644 --- a/src/type/indexed/indexed-property-keys.ts +++ b/src/type/indexed/indexed-property-keys.ts @@ -41,13 +41,11 @@ import { IsTemplateLiteral, IsUnion, IsLiteral, IsNumber, IsInteger } from '../g // FromTemplateLiteral // ------------------------------------------------------------------ // prettier-ignore -type TFromTemplateLiteral<TemplateLiteral extends TTemplateLiteral, - Result extends string[] = TTemplateLiteralGenerate<TemplateLiteral> -> = Result +type TFromTemplateLiteral<TemplateLiteral extends TTemplateLiteral, Keys extends string[] = TTemplateLiteralGenerate<TemplateLiteral>> = (Keys) // prettier-ignore function FromTemplateLiteral<TemplateLiteral extends TTemplateLiteral>(templateLiteral: TemplateLiteral): TFromTemplateLiteral<TemplateLiteral> { - const result = TemplateLiteralGenerate(templateLiteral) as string[] - return result.map(S => S.toString()) as never + const keys = TemplateLiteralGenerate(templateLiteral) as string[] + return keys.map(key => key.toString()) as never } // ------------------------------------------------------------------ // FromUnion @@ -59,9 +57,9 @@ type TFromUnion<Types extends TSchema[], Result extends string[] = []> = ( : Result ) // prettier-ignore -function FromUnion<Type extends TSchema[]>(type: Type): TFromUnion<Type> { +function FromUnion<Types extends TSchema[]>(types: Types): TFromUnion<Types> { const result = [] as string[] - for(const left of type) result.push(...IndexPropertyKeys(left)) + for(const type of types) result.push(...IndexPropertyKeys(type)) return result as never } // ------------------------------------------------------------------ @@ -74,23 +72,23 @@ type TFromLiteral<LiteralValue extends TLiteralValue> = ( : [] ) // prettier-ignore -function FromLiteral<LiteralValue extends TLiteralValue>(T: LiteralValue): TFromLiteral<LiteralValue> { +function FromLiteral<LiteralValue extends TLiteralValue>(literalValue: LiteralValue): TFromLiteral<LiteralValue> { return ( - [(T as string).toString()] // TS 5.4 observes TLiteralValue as not having a toString() + [(literalValue as string).toString()] // TS 5.4 observes TLiteralValue as not having a toString() ) as never } // ------------------------------------------------------------------ -// IndexedKeyResolve +// IndexPropertyKeys // ------------------------------------------------------------------ // prettier-ignore -export type TIndexPropertyKeys<Type extends TSchema, Result extends PropertyKey[] = ( - Type extends TTemplateLiteral ? TFromTemplateLiteral<Type> : - Type extends TUnion<infer Types extends TSchema[]> ? TFromUnion<Types> : - Type extends TLiteral<infer LiteralValue extends TLiteralValue> ? TFromLiteral<LiteralValue> : +export type TIndexPropertyKeys<Type extends TSchema> = ( + Type extends TTemplateLiteral ? TFromTemplateLiteral<Type> : + Type extends TUnion<infer Types extends TSchema[]> ? TFromUnion<Types> : + Type extends TLiteral<infer Value extends TLiteralValue> ? TFromLiteral<Value> : Type extends TNumber ? ['[number]'] : Type extends TInteger ? ['[number]'] : [] -)> = Result +) /** Returns a tuple of PropertyKeys derived from the given TSchema */ // prettier-ignore export function IndexPropertyKeys<Type extends TSchema>(type: Type): TIndexPropertyKeys<Type> { diff --git a/src/type/indexed/indexed.ts b/src/type/indexed/indexed.ts index 5598b034..541c6e73 100644 --- a/src/type/indexed/indexed.ts +++ b/src/type/indexed/indexed.ts @@ -27,70 +27,45 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import { CreateType } from '../create/type' +import { TypeBoxError } from '../error/index' + 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 Assert } from '../helpers/index' +import { type TComputed, Computed } from '../computed/index' +import { type TNever, Never } from '../never/index' +import { type TArray } from '../array/index' +import { type TIntersect } from '../intersect/index' +import { type TMappedResult, type TMappedKey } from '../mapped/index' import { type TObject, type TProperties } from '../object/index' -import { type Ensure, type Assert } from '../helpers/index' -import { Never, type TNever } from '../never/index' +import { type TUnion } from '../union/index' import { type TRecursive } from '../recursive/index' -import { type TIntersect } from '../intersect/index' -import { TMappedResult, type TMappedKey } from '../mapped/index' -import { Union, type TUnion } from '../union/index' +import { type TRef } from '../ref/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 -// ------------------------------------------------------------------ -// prettier-ignore -// type TFromComputed<Target extends string, Parameters extends TSchema[]> = Ensure< -// TComputed<'Partial', [TComputed<Target, Parameters>]> -// > -// // prettier-ignore -// function FromComputed<Target extends string, Parameters extends TSchema[]>(target: Target, parameters: Parameters): TFromComputed<Target, Parameters> { -// return Computed('Partial', [Computed(target, parameters)]) as never -// } -// // ------------------------------------------------------------------ -// // FromRef -// // ------------------------------------------------------------------ -// // prettier-ignore -// type TFromRef<Ref extends string> = Ensure< -// TComputed<'Partial', [TRef<Ref>]> -// > -// // prettier-ignore -// function FromRef<Ref extends string>($ref: Ref): TFromRef<Ref> { -// return Computed('Partial', [Ref($ref)]) as never -// } +import { IsArray, IsIntersect, IsObject, IsMappedKey, IsMappedResult, IsNever, IsSchema, IsTuple, IsUnion, IsRef } from '../guard/kind' // ------------------------------------------------------------------ // FromRest // ------------------------------------------------------------------ // prettier-ignore -type TFromRest<T extends TSchema[], K extends PropertyKey, Result extends TSchema[] = []> = ( - T extends [infer L extends TSchema, ...infer R extends TSchema[]] - ? TFromRest<R, K, [...Result, Assert<TIndexFromPropertyKey<L, K>, TSchema>]> +type TFromRest<Types extends TSchema[], Key extends PropertyKey, Result extends TSchema[] = []> = ( + Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]] + ? TFromRest<Right, Key, [...Result, Assert<TIndexFromPropertyKey<Left, Key>, TSchema>]> : Result ) // prettier-ignore -function FromRest<Types extends TSchema[], K extends PropertyKey>(types: [...Types], key: K): TFromRest<Types, K> { - return types.map(left => IndexFromPropertyKey(left, key)) as never +function FromRest<Types extends TSchema[], Key extends PropertyKey>(types: [...Types], key: Key): TFromRest<Types, Key> { + return types.map(type => IndexFromPropertyKey(type, key)) as never } // ------------------------------------------------------------------ // FromIntersectRest @@ -105,7 +80,7 @@ type TFromIntersectRest<Types extends TSchema[], Result extends TSchema[] = []> ) // prettier-ignore function FromIntersectRest<Types extends TSchema[]>(types: [...Types]): TFromIntersectRest<Types> { - return types.filter(left => !IsNever(left)) as never + return types.filter(type => !IsNever(type)) as never } // prettier-ignore type TFromIntersect<Types extends TSchema[], Key extends PropertyKey> = ( @@ -171,21 +146,17 @@ function FromUnion<Types extends TSchema[], Key extends PropertyKey>(types: [... // ------------------------------------------------------------------ // FromTuple // ------------------------------------------------------------------ - // prettier-ignore -type TFromTuple<Types extends TSchema[], Key extends PropertyKey, Result extends TSchema = ( - Key extends '[number]' ? TUnionEvaluated<Types> : - Key extends keyof Types - ? Types[Key] extends infer Type extends TSchema - ? Type - : TNever - : TNever -)> = Result +type TFromTuple<Types extends TSchema[], Key extends PropertyKey> = ( + Key extends keyof Types ? Types[Key] : + Key extends '[number]' ? TUnionEvaluated<Types> : + TNever +) // prettier-ignore function FromTuple<Types extends TSchema[], Key extends PropertyKey>(types: [...Types], key: Key): TFromTuple<Types, Key> { return ( - key === '[number]' ? UnionEvaluated(types) : key in types ? types[key as number] : + key === '[number]' ? UnionEvaluated(types) : Never() ) as never } @@ -194,20 +165,25 @@ function FromTuple<Types extends TSchema[], Key extends PropertyKey>(types: [... // ------------------------------------------------------------------ // prettier-ignore type TFromArray<Type extends TSchema, Key extends PropertyKey> = ( - Key extends '[number]' ? Type : TNever + Key extends '[number]' + ? Type + : TNever ) // prettier-ignore -function FromArray<Type extends TSchema, Key extends PropertyKey>(type: Type, key: Key): TFromArray<Type, Key> { - // ... ? - return (key === '[number]' ? type : Never()) as never +function FromArray<Type extends TSchema, Key extends PropertyKey>(type: Type, key: Key): TFromArray<Type, Key> { + return ( + key === '[number]' + ? type + : Never() + ) as never } // ------------------------------------------------------------------ // FromProperty // ------------------------------------------------------------------ -type AssertPropertyKey<T extends unknown> = Assert<T, string | number> +type AssertPropertyKey<T> = Assert<T, string | number> // prettier-ignore -type TFromProperty<Properties extends TProperties, Key extends PropertyKey, Result extends TSchema = ( +type TFromProperty<Properties extends TProperties, Key extends PropertyKey> = ( // evaluate for string keys Key extends keyof Properties ? Properties[Key] @@ -215,32 +191,32 @@ type TFromProperty<Properties extends TProperties, Key extends PropertyKey, Resu : `${AssertPropertyKey<Key>}` extends `${AssertPropertyKey<keyof Properties>}` ? Properties[AssertPropertyKey<Key>] : TNever -)> = Result +) // prettier-ignore -function FromProperty<Properties extends TProperties, Key extends PropertyKey>(properties: Properties, key: Key): TFromProperty<Properties, Key> { - return (key in properties ? properties[key as string] : Never()) as never +function FromProperty<Properties extends TProperties, Key extends PropertyKey>(properties: Properties, propertyKey: Key): TFromProperty<Properties, Key> { + return (propertyKey in properties ? properties[propertyKey as string] : Never()) as never } // ------------------------------------------------------------------ // FromKey // ------------------------------------------------------------------ // prettier-ignore export type TIndexFromPropertyKey<Type extends TSchema, Key extends PropertyKey> = ( - Type extends TRecursive<infer S extends TSchema> ? TIndexFromPropertyKey<S, Key> : - Type extends TIntersect<infer S extends TSchema[]> ? TFromIntersect<S, Key> : - Type extends TUnion<infer S extends TSchema[]> ? TFromUnion<S, Key> : - Type extends TTuple<infer S extends TSchema[]> ? TFromTuple<S, Key> : - Type extends TArray<infer S extends TSchema> ? TFromArray<S, Key> : - Type extends TObject<infer S extends TProperties> ? TFromProperty<S, Key> : + Type extends TRecursive<infer Type extends TSchema> ? TIndexFromPropertyKey<Type, Key> : + Type extends TIntersect<infer Types extends TSchema[]> ? TFromIntersect<Types, Key> : + Type extends TUnion<infer Types extends TSchema[]> ? TFromUnion<Types, Key> : + Type extends TTuple<infer Types extends TSchema[]> ? TFromTuple<Types, Key> : + Type extends TArray<infer Type extends TSchema> ? TFromArray<Type, Key> : + Type extends TObject<infer Properties extends TProperties> ? TFromProperty<Properties, Key> : TNever ) // prettier-ignore -export function IndexFromPropertyKey<Type extends TSchema, Key extends PropertyKey>(type: Type, key: Key): TIndexFromPropertyKey<Type, Key> { +export function IndexFromPropertyKey<Type extends TSchema, Key extends PropertyKey>(type: Type, propertyKey: Key): TIndexFromPropertyKey<Type, Key> { return ( - 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) : + IsIntersect(type) ? FromIntersect(type.allOf, propertyKey) : + IsUnion(type) ? FromUnion(type.anyOf, propertyKey) : + IsTuple(type) ? FromTuple(type.items ?? [], propertyKey) : + IsArray(type) ? FromArray(type.items, propertyKey) : + IsObject(type) ? FromProperty(type.properties, propertyKey) : Never() ) as never } @@ -255,76 +231,70 @@ export type TIndexFromPropertyKeys<Type extends TSchema, PropertyKeys extends Pr ) // prettier-ignore export function IndexFromPropertyKeys<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: [...PropertyKeys]): TIndexFromPropertyKeys<Type, PropertyKeys> { - return propertyKeys.map(left => IndexFromPropertyKey(type, left)) as never + return propertyKeys.map(propertyKey => IndexFromPropertyKey(type, propertyKey)) as never } // ------------------------------------------------------------------ // FromSchema // ------------------------------------------------------------------ // prettier-ignore -type TFromType<Type extends TSchema, PropertyKeys extends PropertyKey[], - Result extends TSchema[] = TIndexFromPropertyKeys<Type, PropertyKeys>, -> = TUnionEvaluated<Result> +type FromSchema<Type extends TSchema, PropertyKeys extends PropertyKey[]> = ( + TUnionEvaluated<TIndexFromPropertyKeys<Type, PropertyKeys>> +) // prettier-ignore -function FromType<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: [...PropertyKeys]): TFromType<Type, PropertyKeys> { - const result = IndexFromPropertyKeys(type, propertyKeys as PropertyKey[]) - return UnionEvaluated(result) as never +function FromSchema<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: [...PropertyKeys]): FromSchema<Type, PropertyKeys> { + return ( + UnionEvaluated(IndexFromPropertyKeys(type, propertyKeys as PropertyKey[])) + ) as never } // ------------------------------------------------------------------ -// UnionFromPropertyKeys +// FromSchema // ------------------------------------------------------------------ // prettier-ignore -type TUnionFromPropertyKeys<PropertyKeys extends PropertyKey[], Result extends TLiteral[] = []> = ( - PropertyKeys extends [infer Key extends PropertyKey, ...infer Rest extends PropertyKey[]] - ? Key extends TLiteralValue - ? TUnionFromPropertyKeys<Rest, [...Result, TLiteral<Key>]> - : TUnionFromPropertyKeys<Rest, [...Result]> - : TUnionEvaluated<Result> +export type TIndexFromComputed<Type extends TSchema, Key extends TSchema> = ( + TComputed<'Index', [Type, Key]> ) // prettier-ignore -function UnionFromPropertyKeys<PropertyKeys extends PropertyKey[]>(propertyKeys: PropertyKeys): TUnionFromPropertyKeys<PropertyKeys> { - const result = propertyKeys.reduce((result, key) => IsLiteralValue(key) ? [...result, Literal(key)]: result, [] as TLiteral[]) - return UnionEvaluated(result) as never +export function IndexFromComputed<Type extends TSchema, Key extends TSchema>(type: Type, key: Key): TIndexFromComputed<Type, Key> { + return Computed('Index', [type, key]) } // ------------------------------------------------------------------ // TIndex // ------------------------------------------------------------------ -// prettier-ignore (do not export this type) -type TResolvePropertyKeys<Key extends TSchema | PropertyKey[]> = Key extends TSchema ? TIndexPropertyKeys<Key> : Key -// prettier-ignore (do not export this type) -type TResolveTypeKey<Key extends TSchema | PropertyKey[]> = Key extends PropertyKey[] ? TUnionFromPropertyKeys<Key> : Key // prettier-ignore -export type TIndex<Type extends TSchema, Key extends TSchema | PropertyKey[], - IsTypeRef extends boolean = Type extends TRef ? true : false, - IsKeyRef extends boolean = Key extends TRef ? true : false, -> = ( - Key extends TMappedResult ? TIndexFromMappedResult<Type, Key> : - Key extends TMappedKey ? TIndexFromMappedKey<Type, Key> : - [IsTypeRef, IsKeyRef] extends [true, true] ? TComputed<'Index', [Type, TResolveTypeKey<Key>]> : - [IsTypeRef, IsKeyRef] extends [false, true] ? TComputed<'Index', [Type, TResolveTypeKey<Key>]> : - [IsTypeRef, IsKeyRef] extends [true, false] ? TComputed<'Index', [Type, TResolveTypeKey<Key>]> : - TFromType<Type, TResolvePropertyKeys<Key>> +export type TIndex<Type extends TSchema, PropertyKeys extends PropertyKey[]> = ( + FromSchema<Type, PropertyKeys> ) /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index<Type extends TSchema, Key extends PropertyKey[]>(type: Type, key: readonly [...Key], options?: SchemaOptions): TIndex<Type, Key> +export function Index<Type extends TRef, Key extends TSchema>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index<Type extends TSchema, Key extends TMappedKey>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> +export function Index<Type extends TSchema, Key extends TRef>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index<Type extends TSchema, Key extends TMappedResult>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> +export function Index<Type extends TRef, Key extends TRef>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ -export function Index<Type extends TSchema, Key extends TSchema>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> +export function Index<Type extends TSchema, MappedResult extends TMappedResult>(type: Type, mappedResult: MappedResult, options?: SchemaOptions): TIndexFromMappedResult<Type, MappedResult> /** `[Json]` Returns an Indexed property type for the given keys */ -// 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 +export function Index<Type extends TSchema, MappedResult extends TMappedResult>(type: Type, mappedResult: MappedResult, options?: SchemaOptions): TIndexFromMappedResult<Type, MappedResult> +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index<Type extends TSchema, MappedKey extends TMappedKey>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TIndexFromMappedKey<Type, MappedKey> +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index<Type extends TSchema, Key extends TSchema, PropertyKeys extends PropertyKey[] = TIndexPropertyKeys<Key>>(T: Type, K: Key, options?: SchemaOptions): TIndex<Type, PropertyKeys> +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: readonly [...PropertyKeys], options?: SchemaOptions): TIndex<Type, PropertyKeys> +/** `[Json]` Returns an Indexed property type for the given keys */ +export function Index(type: TSchema, key: any, options?: SchemaOptions): any { + // computed-type + if (IsRef(type) || IsRef(key)) { + const error = `Index types using Ref parameters require both Type and Key to be of TSchema` + if (!IsSchema(type) || !IsSchema(key)) throw new TypeBoxError(error) + return Computed('Index', [type, key]) + } + // mapped-types + if (IsMappedResult(key)) return IndexFromMappedResult(type, key, options) + if (IsMappedKey(key)) return IndexFromMappedKey(type, key, options) + // prettier-ignore + return CreateType( + IsSchema(key) + ? FromSchema(type, IndexPropertyKeys(key)) + : FromSchema(type, key as string[]) + , options) as never } diff --git a/src/type/module/compute.ts b/src/type/module/compute.ts index b2ee6e78..8527ab13 100644 --- a/src/type/module/compute.ts +++ b/src/type/module/compute.ts @@ -35,8 +35,8 @@ 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 { TEnum, TEnumRecord } from '../enum/index' +import { Index, type TIndex, type TIndexPropertyKeys } from '../indexed/index' +import { TEnum, type TEnumRecord } from '../enum/index' import { Function as FunctionType, type TFunction } from '../function/index' import { Intersect, type TIntersect, type TIntersectEvaluated } from '../intersect/index' import { Iterator, type TIterator } from '../iterator/index' @@ -119,7 +119,14 @@ function FromAwaited<Parameters extends TSchema[]>(parameters: Parameters): TFro // ------------------------------------------------------------------ // prettier-ignore type TFromIndex<Parameters extends TSchema[]> = ( - Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] ? TIndex<T0, T1> : never + Parameters extends [infer T0 extends TSchema, infer T1 extends TSchema] + // Note: This inferred result check is required to mitgate a "as never" + // assertion on FromComputed resolution. This should be removed when + // reimplementing TIndex to use TSchema as the primary key indexer. + ? TIndex<T0, TIndexPropertyKeys<T1>> extends infer Result extends TSchema + ? Result + : never + : never ) // prettier-ignore function FromIndex<Parameters extends TSchema[]>(parameters: Parameters): TFromIndex<Parameters> { @@ -370,10 +377,7 @@ export function FromType<ModuleProperties extends TProperties, Type extends TSch // Traveral KindGuard.IsArray(type) ? CreateType(FromArray(moduleProperties, type.items), type) : KindGuard.IsAsyncIterator(type) ? CreateType(FromAsyncIterator(moduleProperties, type.items), type) : - // 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.IsComputed(type) ? CreateType(FromComputed(moduleProperties, type.target, type.parameters)) : KindGuard.IsConstructor(type) ? CreateType(FromConstructor(moduleProperties, type.parameters, type.returns), type) : KindGuard.IsFunction(type) ? CreateType(FromFunction(moduleProperties, type.parameters, type.returns), type) : KindGuard.IsIntersect(type) ? CreateType(FromIntersect(moduleProperties, type.allOf), type) : diff --git a/src/type/type/json.ts b/src/type/type/json.ts index f7efb99c..8cbb88ef 100644 --- a/src/type/type/json.ts +++ b/src/type/type/json.ts @@ -35,7 +35,7 @@ import { Enum, type TEnum, type TEnumKey, type TEnumValue } from '../enum/index' import { Exclude, type TExclude, type TExcludeFromMappedResult, type TExcludeFromTemplateLiteral } from '../exclude/index' import { Extends, type TExtends, type TExtendsFromMappedKey, type TExtendsFromMappedResult } from '../extends/index' import { Extract, type TExtract, type TExtractFromMappedResult, type TExtractFromTemplateLiteral } from '../extract/index' -import { Index, TIndex, type TIndexPropertyKeys, type TIndexFromMappedKey, type TIndexFromMappedResult } from '../indexed/index' +import { Index, TIndex, type TIndexPropertyKeys, type TIndexFromMappedKey, type TIndexFromMappedResult, type TIndexFromComputed } from '../indexed/index' 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' @@ -164,13 +164,19 @@ export class JsonTypeBuilder { return Extract(type, union, options) } /** `[Json]` Returns an Indexed property type for the given keys */ - public Index<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, key: readonly [...PropertyKeys], options?: SchemaOptions): TIndex<Type, PropertyKeys> + public Index<Type extends TRef, Key extends TSchema>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ - public Index<Type extends TSchema, Key extends TMappedKey>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> + public Index<Type extends TSchema, Key extends TRef>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ - public Index<Type extends TSchema, Key extends TMappedResult>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> + public Index<Type extends TRef, Key extends TRef>(type: Type, key: Key, options?: SchemaOptions): TIndexFromComputed<Type, Key> /** `[Json]` Returns an Indexed property type for the given keys */ - public Index<Type extends TSchema, Key extends TSchema>(type: Type, key: Key, options?: SchemaOptions): TIndex<Type, Key> + public Index<Type extends TSchema, MappedResult extends TMappedResult>(type: Type, mappedResult: MappedResult, options?: SchemaOptions): TIndexFromMappedResult<Type, MappedResult> + /** `[Json]` Returns an Indexed property type for the given keys */ + public Index<Type extends TSchema, MappedKey extends TMappedKey>(type: Type, mappedKey: MappedKey, options?: SchemaOptions): TIndexFromMappedKey<Type, MappedKey> + /** `[Json]` Returns an Indexed property type for the given keys */ + public Index<Type extends TSchema, Key extends TSchema, PropertyKeys extends PropertyKey[] = TIndexPropertyKeys<Key>>(T: Type, K: Key, options?: SchemaOptions): TIndex<Type, PropertyKeys> + /** `[Json]` Returns an Indexed property type for the given keys */ + public Index<Type extends TSchema, PropertyKeys extends PropertyKey[]>(type: Type, propertyKeys: readonly [...PropertyKeys], options?: SchemaOptions): TIndex<Type, PropertyKeys> /** `[Json]` Returns an Indexed property type for the given keys */ public Index(type: TSchema, key: any, options?: SchemaOptions): any { return Index(type, key, options)