Skip to content

Commit

Permalink
Reimplement Index Types
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Nov 24, 2023
1 parent bad253a commit 619d9b1
Show file tree
Hide file tree
Showing 8 changed files with 285 additions and 210 deletions.
81 changes: 55 additions & 26 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,25 +42,28 @@ import {
UnionToTuple,
PatternNumber,
Increment,
Accessor,
Indexer,
Assert
AccessResolver,
IndexResolver,
Assert,
} from '@sinclair/typebox'

// prettier-ignore
export namespace KeyOf {
export namespace KeyResolver {
// ----------------------------------------------------------------
// Intersect
// ----------------------------------------------------------------
export type Intersect<T extends TSchema[]> =
export type Intersect<T extends TSchema[]> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? [...Resolve<L>, ...Intersect<R>]
: []
export function Intersect(T: TSchema[]): string[] {
)
export function Intersect<const T extends TSchema[]>(T: T): Intersect<T> {
const [L, ...R] = T
return T.length > 0
? [...Resolve(L), ...Intersect(R)]
: []
return (
T.length > 0
? [...Resolve(L), ...Intersect(R)]
: []
) as Intersect<T>
}
// ----------------------------------------------------------------
// Union
Expand All @@ -72,30 +75,42 @@ export namespace KeyOf {
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
export type Properties<T extends TProperties> = UnionToTuple<keyof T>
export function Properties(T: TProperties): string[] {
return globalThis.Object.getOwnPropertyNames(T)
export type Properties<T extends TProperties> = (
UnionToTuple<keyof T>
)
export function Properties<T extends TProperties>(T: T): Properties<T> {
return (
globalThis.Object.getOwnPropertyNames(T)
) as Properties<T>
}
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
export type Array<_ extends TSchema> = ['number']
export function Array(T: TProperties): string[] {
return ['number']
export type Array<_ extends TSchema> = (
['number']
)
export function Array<_ extends TSchema>(_: _): Array<_> {
return (
['number']
)
}
// ----------------------------------------------------------------
// Tuple
// ----------------------------------------------------------------
export type TupleNext<I extends string[] = []> =
export type TupleNext<I extends string[] = []> = (
I extends [infer L extends string, ...infer _]
? Increment.Next<L>
: '0'
export type Tuple<T extends TSchema[], I extends string[] = []> =
)
export type Tuple<T extends TSchema[], I extends string[] = []> = (
T extends [infer _, ...infer R extends TSchema[]]
? Tuple<R, [TupleNext<I>, ...I]>
: I
export function Tuple(T: TSchema[]): string[] {
return T.map((_, index) => index.toString()).reverse() // ?
)
export function Tuple<const T extends TSchema[]>(T: T): Tuple<T> {
return (
T.map((_, index) => index.toString())
) as Tuple<T>
}
// ----------------------------------------------------------------
// Resolve
Expand All @@ -108,16 +123,30 @@ export namespace KeyOf {
T extends TTuple<infer S> ? Tuple<S> :
[]
)
export function Resolve(T: TSchema): string[] {
return []
export function Resolve<T extends TSchema>(T: T): Resolve<T> {
return (
TypeGuard.TIntersect(T) ? Intersect(T.allOf) :
TypeGuard.TUnion(T) ? Union(T.anyOf) :
TypeGuard.TObject(T) ? Object(T.properties) :
TypeGuard.TArray(T) ? Array(T.items) :
TypeGuard.TTuple(T) ? Tuple(T.items ?? []) :
[]
)
}
}

type X = KeyOf.Resolve<TObject<{
x: TNumber,
y: TNumber,
z: TNumber
}>>
const K = KeyResolver.Resolve(Type.Object({
x: Type.Number()
}))

const I = IndexResolver.Resolve(Type.TemplateLiteral('a${1|2|3}'))

const X = AccessResolver.Union([Type.Object({
a1: Type.String()
}), Type.Object({
a2: Type.Number()
})] , 'a1')


type A = { x: number } | { x: number }
type K = keyof A
Expand Down
2 changes: 1 addition & 1 deletion examples/next/indexer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TypeSystem } from '@sinclair/typebox/system'
import { TypeCompiler } from '@sinclair/typebox/compiler'
import { Value, ValuePointer } from '@sinclair/typebox/value'
import { Type, Accessor, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralResolver, TypeGuard, TIntersect, TUnion, TTemplateLiteral, IsTemplateLiteralFiniteCheck, UnionToTuple, Static, TSchema, TLiteralValue, TLiteral, TNumber, TInteger, TBigInt, TString, IndexerOldOptions, PatternNumber } from '@sinclair/typebox'
import { Type, AccessResolver, TemplateLiteralParser, TemplateLiteralFinite, TemplateLiteralResolver, TypeGuard, TIntersect, TUnion, TTemplateLiteral, IsTemplateLiteralFiniteCheck, UnionToTuple, Static, TSchema, TLiteralValue, TLiteral, TNumber, TInteger, TBigInt, TString, KeyResolverOptions, PatternNumber } from '@sinclair/typebox'
import { TObject } from '@sinclair/typebox'

const A = Type.Index(Type.Object({
Expand Down
8 changes: 4 additions & 4 deletions examples/typedef/typedef.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,13 +65,13 @@ export interface TBoolean extends Types.TSchema {
// --------------------------------------------------------------------------
// TUnion
// --------------------------------------------------------------------------
type InferUnion<T extends TStruct[], D extends string, Index = string> = T extends [infer L, ...infer R]
? Types.Evaluate<{ [_ in D]: Index } & Types.Static<Types.AssertType<L>>> | InferUnion<Types.AssertRest<R>, D, Increment<Types.Assert<Index, string>>>
: never
// type InferUnion<T extends TStruct[], D extends string, Index = string> = T extends [infer L, ...infer R]
// ? Types.Evaluate<{ [_ in D]: Index } & Types.Static<Types.AssertType<L>>> | InferUnion<Types.AssertRest<R>, D, Increment<Types.Assert<Index, string>>>
// : never

export interface TUnion<T extends TStruct[] = TStruct[], D extends string = string> extends Types.TSchema {
[Types.Kind]: 'TypeDef:Union'
static: InferUnion<T, D, '0'>
static: unknown //InferUnion<T, D, '0'>
discriminator: D,
mapping: T
}
Expand Down
4 changes: 2 additions & 2 deletions src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,11 +253,11 @@ export namespace TypeCompiler {
function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], value: string): IterableIterator<string> {
const check1 = schema.allOf.map((schema: Types.TSchema) => CreateExpression(schema, references, value)).join(' && ')
if (schema.unevaluatedProperties === false) {
const keyCheck = CreateVariable(`${new RegExp(Types.IndexerOld.Pattern(schema))};`)
const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.Pattern(schema))};`)
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key))`
yield `(${check1} && ${check2})`
} else if (Types.TypeGuard.TSchema(schema.unevaluatedProperties)) {
const keyCheck = CreateVariable(`${new RegExp(Types.IndexerOld.Pattern(schema))};`)
const keyCheck = CreateVariable(`${new RegExp(Types.KeyResolver.Pattern(schema))};`)
const check2 = `Object.getOwnPropertyNames(${value}).every(key => ${keyCheck}.test(key) || ${CreateExpression(schema.unevaluatedProperties, references, `${value}[key]`)})`
yield `(${check1} && ${check2})`
} else {
Expand Down
4 changes: 2 additions & 2 deletions src/errors/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,15 +262,15 @@ function* TIntersect(schema: Types.TIntersect, references: Types.TSchema[], path
}
}
if (schema.unevaluatedProperties === false) {
const keyCheck = new RegExp(Types.IndexerOld.Pattern(schema))
const keyCheck = new RegExp(Types.KeyResolver.Pattern(schema))
for (const valueKey of Object.getOwnPropertyNames(value)) {
if (!keyCheck.test(valueKey)) {
yield Create(ValueErrorType.IntersectUnevaluatedProperties, schema, `${path}/${valueKey}`, value)
}
}
}
if (typeof schema.unevaluatedProperties === 'object') {
const keyCheck = new RegExp(Types.IndexerOld.Pattern(schema))
const keyCheck = new RegExp(Types.KeyResolver.Pattern(schema))
for (const valueKey of Object.getOwnPropertyNames(value)) {
if (!keyCheck.test(valueKey)) {
const next = Visit(schema.unevaluatedProperties, references, `${path}/${valueKey}`, value[valueKey]).next()
Expand Down
Loading

0 comments on commit 619d9b1

Please sign in to comment.