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 eaf9e78 commit 1f5b632
Show file tree
Hide file tree
Showing 6 changed files with 235 additions and 145 deletions.
64 changes: 27 additions & 37 deletions examples/index.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,31 @@
import { Value } from '@sinclair/typebox/value'
import { TSchema, Type, Evaluate } from '@sinclair/typebox'
import { KeyOfStringResolver, IndexedTypeResolver, Logic as PropertySet } from '@sinclair/typebox/type'
import { TSchema, Type, TypeGuard, Discard, Evaluate, Ensure, TObject, Kind } from '@sinclair/typebox'
import { KeyOfStringResolver, IndexedTypeResolver, OmitResolver } from '@sinclair/typebox/type'

export namespace OmitResolver {
export type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
// ----------------------------------------------------------------
// Reduce
// ----------------------------------------------------------------
export type Reduce<T extends TSchema, K extends PropertyKey[]> = K extends [infer L extends PropertyKey, ...infer R extends PropertyKey[]] ? { [_ in L]: IndexedTypeResolver.Resolve<T, [L]> } & Reduce<T, R> : {}
export function Reduce<T extends TSchema, K extends PropertyKey[]>(T: T, K: [...K]): Reduce<T, K> {
return K.reduce((acc, key) => {
return { ...acc, [key]: IndexedTypeResolver.Resolve(T, [key]) }
}, {}) as Reduce<T, K>
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
export type Resolve<T extends TSchema, K extends PropertyKey[], A extends PropertyKey[] = KeyOfStringResolver.Resolve<T>, B extends PropertyKey[] = PropertySet.Complement<A, K>> = Evaluate<Reduce<T, B>>
// const R = TypeGuard.TUnion(
// Type.Union([
// Type.Object({
// x: Type.Number(),
// }),
// {} as any,
// ]),
// )
console.log(
TypeGuard.TSchema(
Type.Object({
y: {} as any,
}),
),
'?',
)

export function Resolve<T extends TSchema, K extends PropertyKey[]>(T: T, K: [...K]): Resolve<T, K> {
const A = KeyOfStringResolver.Resolve(T) as PropertyKey[]
const B = PropertySet.Complement(A, K) as PropertyKey[]
return Reduce(T, B) as Resolve<T, K>
}
}
// // @ts-ignore
// Assert.IsEqual(T.properties.x, undefined)
// // @ts-ignore
// Assert.IsEqual(T.properties.y, undefined)
// // @ts-ignore
// Assert.IsEqual(T.required, undefined)

const A = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
})
const B = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
})
const T = Type.Intersect([Type.Intersect([A, B]), Type.Intersect([A, B]), Type.Intersect([A, B])])

const R = OmitResolver.Resolve(T, ['x'])
console.log(JSON.stringify(R, null, 2))
// const K = Type.TemplateLiteral('A${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}${0|1}')
// const T = Type.Record(K, Type.Null())
// const O = Type.Omit(T, ['asd'])
134 changes: 87 additions & 47 deletions src/type/guard/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import { TypeRegistry } from '../registry/index'
import { ValueGuard } from './value'
import {
TransformOptions,
Expand Down Expand Up @@ -77,7 +76,40 @@ import {
// ------------------------------------------------------------------
export class TypeGuardUnknownTypeError extends Error {}
/** Provides functions to test if JavaScript values are TypeBox types */
// prettier-ignore
export namespace TypeGuard {
const KnownKinds = [
'Any',
'Array',
'AsyncIterator',
'BigInt',
'Boolean',
'Constructor',
'Date',
'Function',
'Integer',
'Intersect',
'Iterator',
'Literal',
'Never',
'Not',
'Null',
'Number',
'Object',
'Promise',
'Record',
'Ref',
'String',
'Symbol',
'TemplateLiteral',
'This',
'Tuple',
'Undefined',
'Union',
'Uint8Array',
'Unknown',
'Void'
]
function IsPattern(value: unknown): value is string {
try {
new RegExp(value as string)
Expand Down Expand Up @@ -121,6 +153,17 @@ export namespace TypeGuard {
return ValueGuard.IsUndefined(value) || TSchema(value)
}
// ----------------------------------------------------------------
// Modifiers
// ----------------------------------------------------------------
/** Returns true if this value has a Readonly symbol */
export function TReadonly<T extends TSchema>(schema: T): schema is TReadonly<T> {
return ValueGuard.IsObject(schema) && schema[Readonly] === 'Readonly'
}
/** Returns true if this value has a Optional symbol */
export function TOptional<T extends TSchema>(schema: T): schema is TOptional<T> {
return ValueGuard.IsObject(schema) && schema[Optional] === 'Optional'
}
// ----------------------------------------------------------------
// Types
// ----------------------------------------------------------------
/** Returns true if the given value is TAny */
Expand Down Expand Up @@ -254,11 +297,7 @@ export namespace TypeGuard {
}
/** Returns true if the given value is a TKind with the given name. */
export function TKindOf<T extends string>(schema: unknown, kind: T): schema is Record<PropertyKey, unknown> & { [Kind]: T } {
return TKind(schema) && schema[Kind] === kind
}
/** Returns true if the given value is TKind */
export function TKind(schema: unknown): schema is Record<PropertyKey, unknown> & { [Kind]: string } {
return ValueGuard.IsObject(schema) && Kind in schema && ValueGuard.IsString(schema[Kind])
return ValueGuard.IsObject(schema) && Kind in schema && schema[Kind] === kind
}
/** Returns true if the given value is TLiteral<string> */
export function TLiteralString(schema: unknown): schema is TLiteral<string> {
Expand Down Expand Up @@ -331,10 +370,10 @@ export namespace TypeGuard {
schema.type === 'object' &&
IsOptionalString(schema.$id) &&
ValueGuard.IsObject(schema.properties) &&
Object.entries(schema.properties).every(([key, schema]) => IsControlCharacterFree(key) && TSchema(schema)) &&
IsAdditionalProperties(schema.additionalProperties) &&
IsOptionalNumber(schema.minProperties) &&
IsOptionalNumber(schema.maxProperties) &&
Object.entries(schema.properties).every(([key, schema]) => IsControlCharacterFree(key) && TSchema(schema))
IsOptionalNumber(schema.maxProperties)
)
}
/** Returns true if the given value is TPromise */
Expand Down Expand Up @@ -502,52 +541,53 @@ export namespace TypeGuard {
IsOptionalString(schema.$id)
)
}
/** Returns true if this value has a Readonly symbol */
export function TReadonly<T extends TSchema>(schema: T): schema is TReadonly<T> {
return ValueGuard.IsObject(schema) && schema[Readonly] === 'Readonly'
}
/** Returns true if this value has a Optional symbol */
export function TOptional<T extends TSchema>(schema: T): schema is TOptional<T> {
return ValueGuard.IsObject(schema) && schema[Optional] === 'Optional'
/** Returns true if the given value is TKind */
export function TKind(schema: unknown): schema is Record<PropertyKey, unknown> & { [Kind]: string } {
return (
ValueGuard.IsObject(schema) &&
Kind in schema
&& ValueGuard.IsString(schema[Kind]) &&
!KnownKinds.includes(schema[Kind])
)
}
/** Returns true if the given value is TSchema */
export function TSchema(schema: unknown): schema is TSchema {
// prettier-ignore
return (
ValueGuard.IsObject(schema)
) && (
TAny(schema) ||
TArray(schema) ||
TBoolean(schema) ||
TBigInt(schema) ||
TAsyncIterator(schema) ||
TConstructor(schema) ||
TDate(schema) ||
TFunction(schema) ||
TInteger(schema) ||
TIntersect(schema) ||
TIterator(schema) ||
TLiteral(schema) ||
TNever(schema) ||
TNot(schema) ||
TNull(schema) ||
TNumber(schema) ||
TObject(schema) ||
TPromise(schema) ||
TRecord(schema) ||
TRef(schema) ||
TString(schema) ||
TSymbol(schema) ||
TTemplateLiteral(schema) ||
TThis(schema) ||
TTuple(schema) ||
TUndefined(schema) ||
TUnion(schema) ||
TUint8Array(schema) ||
TUnknown(schema) ||
TUnsafe(schema) ||
TVoid(schema) ||
(TKind(schema) && TypeRegistry.Has(schema[Kind] as any))
TAny(schema) ||
TArray(schema) ||
TBoolean(schema) ||
TBigInt(schema) ||
TAsyncIterator(schema) ||
TConstructor(schema) ||
TDate(schema) ||
TFunction(schema) ||
TInteger(schema) ||
TIntersect(schema) ||
TIterator(schema) ||
TLiteral(schema) ||
TNever(schema) ||
TNot(schema) ||
TNull(schema) ||
TNumber(schema) ||
TObject(schema) ||
TPromise(schema) ||
TRecord(schema) ||
TRef(schema) ||
TString(schema) ||
TSymbol(schema) ||
TTemplateLiteral(schema) ||
TThis(schema) ||
TTuple(schema) ||
TUndefined(schema) ||
TUnion(schema) ||
TUint8Array(schema) ||
TUnknown(schema) ||
TUnsafe(schema) ||
TVoid(schema) ||
TKind(schema)
)
}
}
1 change: 1 addition & 0 deletions src/type/resolve/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export * from './intrinsic/index'
export * from './keyof/index'
export * from './logic/index'
export * from './modifiers/index'
export * from './omit/index'
export * from './record/index'
export * from './template-literal/index'
export * from './union/index'
Loading

0 comments on commit 1f5b632

Please sign in to comment.