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 fb6127f commit 90b2175
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 84 deletions.
50 changes: 4 additions & 46 deletions examples/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,53 +47,11 @@ import {
Assert,
UnionToIntersect,
KeyResolver,
Ensure
Ensure,
} from '@sinclair/typebox'

// ------------------------------------------------------------------
// KeyOfResolver
// ------------------------------------------------------------------
// prettier-ignore
export namespace KeyOfResolver {
// ----------------------------------------------------------------
// Literals
// ----------------------------------------------------------------
export type Literals<T extends TLiteralValue[]> = (
T extends [infer L extends TLiteralValue, ...infer R extends TLiteralValue[]]
? [TLiteral<L>, ...Literals<R>]
: []
)
export function Literals<T extends TLiteralValue[]>(T: [...T]): Literals<T> {
const [L, ...R] = T
return (
T.length > 0
? [Type.Literal(L as TLiteralValue), ...Literals(R)]
: []
) as Literals<T>
}
// ----------------------------------------------------------------
// Resolve
// ----------------------------------------------------------------
export type Resolve<T extends TSchema> = (
Ensure<UnionType.Resolve<Literals<KeyResolver.Resolve<T>>>>
)
export function Resolve<T extends TSchema>(T: T): Resolve<T> {
return (
UnionType.Resolve(Literals(KeyResolver.Resolve(T) as TLiteralValue[]))
) as unknown as Resolve<T>
}
}
const A = Type.KeyOf(Type.Tuple([Type.Number()]))
console.log(A)


const K = KeyOfResolver.Resolve(Type.Tuple([
Type.Number(),
Type.Number(),
Type.Number(),
Type.Number(),
Type.Number(),
Type.Number(),
Type.Number(),
Type.Number(),
]))

console.log(K)
const M = KeyResolver.Resolve(Type.Tuple([Type.Number(), Type.Number(), Type.Number()]))
58 changes: 22 additions & 36 deletions src/typebox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ export type TupleToUnion<T extends any[]> = { [K in keyof T]: T[K] }[number]
export type UnionToIntersect<U> = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never
export type UnionLast<U> = UnionToIntersect<U extends unknown ? (x: U) => 0 : never> extends (x: infer L) => 0 ? L : never
export type UnionToTuple<U, L = UnionLast<U>> = [U] extends [never] ? [] : [...UnionToTuple<Exclude<U, L>>, L]
export type Discard<T extends unknown[], D extends unknown> = T extends [infer L, ...infer R] ? (L extends D ? Discard<R, D> : [L, ...Discard<R, D>]) : []
export type Reverse<T extends unknown[]> = T extends [infer L extends unknown, ...infer R extends unknown[]] ? [...Reverse<R>, L] : []
export type Trim<T> = T extends `${' '}${infer U}` ? Trim<U> : T extends `${infer U}${' '}` ? Trim<U> : T
export type Assert<T, E> = T extends E ? T : never
export type Evaluate<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
Expand Down Expand Up @@ -460,27 +460,7 @@ export interface TIterator<T extends TSchema = TSchema> extends TSchema {
// --------------------------------------------------------------------------
// TKeyOf
// --------------------------------------------------------------------------
// prettier-ignore
export type TKeyOfProperties<T extends TSchema> = Discard<Static<T> extends infer S
? UnionToTuple<{ [K in keyof S]: TLiteral<Assert<K, TLiteralValue>> }[keyof S]>
: [], undefined> // note: optional properties produce undefined types in tuple result. discard.
// prettier-ignore
export type TKeyOfIndicesArray<T extends TSchema[]> = UnionToTuple<keyof T & `${number}`>
// prettier-ignore
export type TKeyOfIndices<T extends TSchema[]> = AssertRest<TKeyOfIndicesArray<T> extends infer R ? {
[K in keyof R]: TLiteral<Assert<R[K], TLiteralValue>>
} : []>
// prettier-ignore
export type TKeyOf<T extends TSchema = TSchema> = (
T extends TRecursive<infer S> ? TKeyOfProperties<S> :
T extends TIntersect ? TKeyOfProperties<T> :
T extends TUnion ? TKeyOfProperties<T> :
T extends TObject ? TKeyOfProperties<T> :
T extends TTuple<infer K> ? TKeyOfIndices<K> :
T extends TArray ? [TNumber] :
T extends TRecord<infer K> ? [K] :
[]
) extends infer R ? UnionType.Resolve<AssertRest<R>> : never

// --------------------------------------------------------------------------
// TLiteral
// --------------------------------------------------------------------------
Expand Down Expand Up @@ -2759,25 +2739,27 @@ export namespace KeyResolver {
? Increment.Next<L>
: '0'
)
export type Tuple<T extends TSchema[], I extends string[] = []> = (
export type TupleCollect<T extends TSchema[], I extends string[] = []> = (
T extends [infer _, ...infer R extends TSchema[]]
? Tuple<R, [TupleNext<I>, ...I]>
? TupleCollect<R, [TupleNext<I>, ...I]>
: I
)
export type Tuple<T extends TSchema[]> = Reverse<TupleCollect<T>>

export function Tuple<T extends TSchema[]>(T: [...T]): Tuple<T> {
return (
T.map((_, index) => index).reverse()
T.map((_, index) => index.toString())
) as Tuple<T>
}
// ----------------------------------------------------------------
// Array
// ----------------------------------------------------------------
export type Array<_ extends TSchema> = (
['number']
['[number]']
)
export function Array<_ extends TSchema>(_: _): Array<_> {
return (
['number']
['[number]']
)
}
// ----------------------------------------------------------------
Expand Down Expand Up @@ -2901,17 +2883,17 @@ export namespace IndexResolver {
T extends TTemplateLiteral ? TemplateLiteral<T> :
T extends TUnion<infer S> ? Union<S> :
T extends TLiteral<infer S> ? Literal<S> :
T extends TNumber ? ['number'] :
T extends TInteger ? ['number'] :
T extends TNumber ? ['[number]'] :
T extends TInteger ? ['[number]'] :
[]
)
export function Resolve<T extends TSchema>(T: T): Resolve<T> {
return [...new Set<string>((
TypeGuard.TTemplateLiteral(T) ? TemplateLiteral(T) :
TypeGuard.TUnion(T) ? Union(T.anyOf) :
TypeGuard.TLiteral(T) ? TLiteral(T.const) :
TypeGuard.TNumber(T) ? ['number'] :
TypeGuard.TInteger(T) ? ['number'] :
TypeGuard.TNumber(T) ? ['[number]'] :
TypeGuard.TInteger(T) ? ['[number]'] :
[]
))] as unknown as Resolve<T>
}
Expand Down Expand Up @@ -2998,13 +2980,13 @@ export namespace AccessResolver {
// ----------------------------------------------------------------
export type Tuple<T extends TSchema[], K extends PropertyKey> = (
K extends keyof T ? T[K] :
K extends 'number' ? UnionType.Resolve<T> :
K extends '[number]' ? UnionType.Resolve<T> :
TNever
)
export function Tuple<T extends TSchema[], K extends PropertyKey>(T: [...T], K: K): Tuple<T, K> {
return (
K in T ? T[K as number] :
K === 'number' ? UnionType.Resolve(T) :
K === '[number]' ? UnionType.Resolve(T) :
Type.Never()
) as Tuple<T, K>
}
Expand All @@ -3018,7 +3000,7 @@ export namespace AccessResolver {
)
export function Array<T extends TSchema, K extends PropertyKey>(T: T, K: K): Array<T, K> {
return (
K === 'number'
K === '[number]'
? T
: Type.Never()
) as Array<T, K>
Expand Down Expand Up @@ -3098,14 +3080,18 @@ export namespace KeyOfResolver {
// ----------------------------------------------------------------
export type Literals<T extends TLiteralValue[]> = (
T extends [infer L extends TLiteralValue, ...infer R extends TLiteralValue[]]
? [TLiteral<L>, ...Literals<R>]
? L extends '[number]'
? [TNumber, ...Literals<R>]
: [TLiteral<L>, ...Literals<R>]
: []
)
export function Literals<T extends TLiteralValue[]>(T: [...T]): Literals<T> {
const [L, ...R] = T
return (
T.length > 0
? [Type.Literal(L as TLiteralValue), ...Literals(R)]
? L === '[number]'
? [Type.Number(), ...Literals(R)]
: [Type.Literal(L as TLiteralValue), ...Literals(R)]
: []
) as Literals<T>
}
Expand Down
4 changes: 2 additions & 2 deletions test/runtime/type/guard/keyof.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ describe('type/guard/TKeyOf', () => {
const T = Type.Tuple([Type.Number(), Type.Null()])
const K = Type.KeyOf(T)
Assert.IsTrue(TypeGuard.TUnion(K))
Assert.IsEqual(K.anyOf[0].const, 0)
Assert.IsEqual(K.anyOf[1].const, 1)
Assert.IsEqual(K.anyOf[0].const, '0')
Assert.IsEqual(K.anyOf[1].const, '1')
})
})

0 comments on commit 90b2175

Please sign in to comment.