Skip to content

Commit

Permalink
Reimplement Indexed Accessors
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Nov 26, 2023
1 parent 747f924 commit e67952f
Show file tree
Hide file tree
Showing 10 changed files with 275 additions and 114 deletions.
2 changes: 1 addition & 1 deletion examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Value } from '@sinclair/typebox/value'
import { TSchema, Type, Static, TypeGuard, Discard, Evaluate, Ensure, TObject, Kind } from '@sinclair/typebox'
import { TSchema, Type, Static, TypeGuard, Evaluate, Ensure, TObject, Kind } from '@sinclair/typebox'
import { PartialResolver, IndexedKeyResolver } from '@sinclair/typebox/type'

const A = Type.Object({ x: Type.Number() })
Expand Down
66 changes: 33 additions & 33 deletions examples/prototypes/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,36 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { Type, ObjectMap, TypeGuard, TSchema, TIntersect, TUnion, TObject, TProperties, TReadonly, AssertProperties, AssertType, AssertRest, Evaluate, ModifiersRemoveReadonly } from '@sinclair/typebox'

// -------------------------------------------------------------------------------------
// TConst
// -------------------------------------------------------------------------------------
// prettier-ignore
export type TConstArray<T extends TSchema[], E extends boolean> = T extends [infer L, ...infer R]
? [TConst<AssertType<L>, E>, ...TConstArray<AssertRest<R>, E>]
: []
// prettier-ignore
export type TConstProperties<T extends TProperties, E extends boolean> = Evaluate<AssertProperties<{
[K in keyof T]: TConst<ModifiersRemoveReadonly<T[K]>, E>
}>>
// prettier-ignore
export type TConst<T extends TSchema, E extends boolean> =
T extends TIntersect<infer S> ? TIntersect<TConstArray<S, false>> :
T extends TUnion<infer S> ? TUnion<TConstArray<S, false>> :
T extends TObject<infer S> ? TObject<TConstProperties<S, false>> :
E extends true ? T : TReadonly<T>
// -------------------------------------------------------------------------------------
// Const
// -------------------------------------------------------------------------------------
/** `[Experimental]` Assigns readonly to all interior properties */
export function Const<T extends TSchema>(schema: T): TConst<T, true> {
const mappable = (TypeGuard.TIntersect(schema) || TypeGuard.TUnion(schema) || TypeGuard.TObject(schema))
// prettier-ignore
return mappable ? ObjectMap.Map(schema, (object) => {
const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
return { ...acc, [key]: Type.Readonly(object.properties[key] )}
}, {} as TProperties)
return Type.Object(properties, {...object})
}, {}) : schema as any
}
// import { Type, ObjectMap, TypeGuard, TSchema, TIntersect, TUnion, TObject, TProperties, TReadonly, AssertProperties, AssertType, AssertRest, Evaluate, ModifiersRemoveReadonly } from '@sinclair/typebox'

// // -------------------------------------------------------------------------------------
// // TConst
// // -------------------------------------------------------------------------------------
// // prettier-ignore
// export type TConstArray<T extends TSchema[], E extends boolean> = T extends [infer L, ...infer R]
// ? [TConst<AssertType<L>, E>, ...TConstArray<AssertRest<R>, E>]
// : []
// // prettier-ignore
// export type TConstProperties<T extends TProperties, E extends boolean> = Evaluate<AssertProperties<{
// [K in keyof T]: TConst<ModifiersRemoveReadonly<T[K]>, E>
// }>>
// // prettier-ignore
// export type TConst<T extends TSchema, E extends boolean> =
// T extends TIntersect<infer S> ? TIntersect<TConstArray<S, false>> :
// T extends TUnion<infer S> ? TUnion<TConstArray<S, false>> :
// T extends TObject<infer S> ? TObject<TConstProperties<S, false>> :
// E extends true ? T : TReadonly<T>
// // -------------------------------------------------------------------------------------
// // Const
// // -------------------------------------------------------------------------------------
// /** `[Experimental]` Assigns readonly to all interior properties */
// export function Const<T extends TSchema>(schema: T): TConst<T, true> {
// const mappable = (TypeGuard.TIntersect(schema) || TypeGuard.TUnion(schema) || TypeGuard.TObject(schema))
// // prettier-ignore
// return mappable ? ObjectMap.Map(schema, (object) => {
// const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
// return { ...acc, [key]: Type.Readonly(object.properties[key] )}
// }, {} as TProperties)
// return Type.Object(properties, {...object})
// }, {}) : schema as any
// }
38 changes: 38 additions & 0 deletions src/type/resolve/discard/discard.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <[email protected]>
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.
---------------------------------------------------------------------------*/

/** Discards properties from record types */
export namespace Discard {
function Key(value: Record<PropertyKey, any>, key: PropertyKey) {
const { [key]: _, ...rest } = value
return rest
}
export function Keys(value: Record<PropertyKey, any>, keys: PropertyKey[]) {
return keys.reduce((acc, key) => Key(acc, key), value)
}
}
29 changes: 29 additions & 0 deletions src/type/resolve/discard/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <[email protected]>
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 './discard'
2 changes: 2 additions & 0 deletions src/type/resolve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ THE SOFTWARE.

export * from './awaited/index'
export * from './composite/index'
export * from './discard/index'
export * from './distinct/index'
export * from './extends/index'
export * from './increment/index'
Expand All @@ -41,5 +42,6 @@ export * from './omit/index'
export * from './partial/index'
export * from './pick/index'
export * from './record/index'
export * from './required/index'
export * from './template-literal/index'
export * from './union/index'
3 changes: 2 additions & 1 deletion src/type/resolve/modifiers/modifiers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { Type, Discard, TypeGuard, TSchema, TIntersect, TUnion, TOptional, TReadonly, Readonly, Optional } from '../../../typebox'
import { Type, TypeGuard, TSchema, TIntersect, TUnion, TOptional, TReadonly, Readonly, Optional } from '../../../typebox'
import { Discard } from '../discard/index'

// ----------------------------------------------------------------
// Modifiers
Expand Down
8 changes: 6 additions & 2 deletions src/type/resolve/partial/partial.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { Type, TSchema, TypeGuard, TObject, TProperties, TIntersect, TUnion, TOptional, TRecursive } from '../../../typebox'
import { Type, TSchema, TypeGuard, TObject, TProperties, TIntersect, TUnion, TOptional, TRecursive, TReadonlyOptional, TReadonly } from '../../../typebox'

// prettier-ignore
export namespace PartialResolver {
Expand Down Expand Up @@ -67,7 +67,11 @@ export namespace PartialResolver {
// Properties
// ----------------------------------------------------------------
export type Properties<T extends TProperties> = Evaluate<{
[K in keyof T]: TOptional<T[K]>
[K in keyof T]:
T[K] extends (TReadonlyOptional<infer S>) ? TReadonlyOptional<S> :
T[K] extends (TReadonly<infer S>) ? TReadonlyOptional<S> :
T[K] extends (TOptional<infer S>) ? TOptional<S> :
TOptional<T[K]>
}>
export function Properties<T extends TProperties>(T: T) {
return globalThis.Object.getOwnPropertyNames(T).reduce((Acc, K) => {
Expand Down
29 changes: 29 additions & 0 deletions src/type/resolve/required/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <[email protected]>
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 './required'
126 changes: 126 additions & 0 deletions src/type/resolve/required/required.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
/*--------------------------------------------------------------------------
@sinclair/typebox
The MIT License (MIT)
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <[email protected]>
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, TypeGuard, TObject, TProperties, TIntersect, TUnion, TOptional, TRecursive, TReadonlyOptional, TReadonly, Optional } from '../../../typebox'
import { Discard } from '../discard'
// return ObjectMap.Map(this.Discard(TypeClone.Type(schema), ['$id', Transform]), (object) => {
// const properties = Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
// return { ...acc, [key]: this.Discard(object.properties[key], [Optional]) as TSchema }
// }, {} as TProperties)
// return this.Object(properties, object /* object used as options to retain other constraints */)
// }, options)

// // ------------------------------------------------------------------
// // TRequired
// // ------------------------------------------------------------------
// export type TRequiredRest<T extends TSchema[]> = AssertRest<{ [K in keyof T]: TRequired<AssertType<T[K]>> }>
// // prettier-ignore
// export type TRequiredProperties<T extends TProperties> = Evaluate<AssertProperties<{
// [K in keyof T]:
// T[K] extends (TReadonlyOptional<infer S>) ? TReadonly<S> :
// T[K] extends (TReadonly<infer S>) ? TReadonly<S> :
// T[K] extends (TOptional<infer S>) ? S :
// T[K]
// }>>
// // prettier-ignore
// export type TRequired<T extends TSchema> =
// T extends TRecursive<infer S> ? TRecursive<TRequired<S>> :
// T extends TIntersect<infer S> ? TIntersect<TRequiredRest<S>> :
// T extends TUnion<infer S> ? TUnion<TRequiredRest<S>> :
// T extends TObject<infer S> ? TObject<TRequiredProperties<S>> :
// T

// prettier-ignore
export namespace RequiredResolver {
export type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
// ----------------------------------------------------------------
// Intersect
// ----------------------------------------------------------------
export type Intersect<T extends TSchema[]> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? [Resolve<L>, ...Intersect<R>]
: []
)
export function Intersect<T extends TSchema[]>(T: [...T]) : Intersect<T> {
const [L, ...R] = T
return (
T.length > 0
? [Resolve(L), ...Intersect(R)]
: []
) as Intersect<T>
}
// ----------------------------------------------------------------
// Union
// ----------------------------------------------------------------
export type Union<T extends TSchema[]> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? [Resolve<L>, ...Union<R>]
: []
)
export function Union<T extends TSchema[]>(T: [...T]): Union<T> {
const [L, ...R] = T
return (
T.length > 0
? [Resolve(L), ...Union(R)]
: []
) as Union<T>
}
// ----------------------------------------------------------------
// Properties
// ----------------------------------------------------------------
export type Properties<T extends TProperties> = Evaluate<{
[K in keyof T]:
T[K] extends (TReadonlyOptional<infer S>) ? TReadonly<S> :
T[K] extends (TReadonly<infer S>) ? TReadonly<S> :
T[K] extends (TOptional<infer S>) ? S :
T[K]
}>
export function Properties<T extends TProperties>(T: T) {
return globalThis.Object.getOwnPropertyNames(T).reduce((Acc, K) => {
return { ...Acc, [K]: Discard.Keys(T[K], [Optional]) as TSchema }
}, {} as TProperties)
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
export type Resolve<T extends TSchema> = (
T extends TRecursive<infer S> ? TRecursive<Resolve<S>> :
T extends TIntersect<infer S> ? TIntersect<Intersect<S>> :
T extends TUnion<infer S> ? TUnion<Union<S>> :
T extends TObject<infer S> ? TObject<Properties<S>> :
TObject<{}>
)
export function Resolve<T extends TSchema>(T: T): Resolve<T> {
return (
TypeGuard.TIntersect(T) ? Type.Intersect(Intersect(T.allOf)) :
TypeGuard.TUnion(T) ? Type.Union(Union(T.anyOf)) :
TypeGuard.TObject(T) ? Type.Object(Properties(T.properties)) :
Type.Object({})
) as Resolve<T>
}
}
Loading

0 comments on commit e67952f

Please sign in to comment.