From 90b217531f1876913477400d94d07fe483362c75 Mon Sep 17 00:00:00 2001 From: sinclair Date: Fri, 24 Nov 2023 15:57:21 +0900 Subject: [PATCH] Reimplement Index Types --- examples/index.ts | 50 +++------------------------ src/typebox.ts | 58 ++++++++++++-------------------- test/runtime/type/guard/keyof.ts | 4 +-- 3 files changed, 28 insertions(+), 84 deletions(-) diff --git a/examples/index.ts b/examples/index.ts index 29c7739c3..bd9b54ab1 100644 --- a/examples/index.ts +++ b/examples/index.ts @@ -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 [infer L extends TLiteralValue, ...infer R extends TLiteralValue[]] - ? [TLiteral, ...Literals] - : [] - ) - export function Literals(T: [...T]): Literals { - const [L, ...R] = T - return ( - T.length > 0 - ? [Type.Literal(L as TLiteralValue), ...Literals(R)] - : [] - ) as Literals - } - // ---------------------------------------------------------------- - // Resolve - // ---------------------------------------------------------------- - export type Resolve = ( - Ensure>>> - ) - export function Resolve(T: T): Resolve { - return ( - UnionType.Resolve(Literals(KeyResolver.Resolve(T) as TLiteralValue[])) - ) as unknown as Resolve - } -} +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()])) diff --git a/src/typebox.ts b/src/typebox.ts index 1ea5e0e7b..f8baaa8d3 100644 --- a/src/typebox.ts +++ b/src/typebox.ts @@ -57,7 +57,7 @@ export type TupleToUnion = { [K in keyof T]: T[K] }[number] export type UnionToIntersect = (U extends unknown ? (arg: U) => 0 : never) extends (arg: infer I) => 0 ? I : never export type UnionLast = UnionToIntersect 0 : never> extends (x: infer L) => 0 ? L : never export type UnionToTuple> = [U] extends [never] ? [] : [...UnionToTuple>, L] -export type Discard = T extends [infer L, ...infer R] ? (L extends D ? Discard : [L, ...Discard]) : [] +export type Reverse = T extends [infer L extends unknown, ...infer R extends unknown[]] ? [...Reverse, L] : [] export type Trim = T extends `${' '}${infer U}` ? Trim : T extends `${infer U}${' '}` ? Trim : T export type Assert = T extends E ? T : never export type Evaluate = T extends infer O ? { [K in keyof O]: O[K] } : never @@ -460,27 +460,7 @@ export interface TIterator extends TSchema { // -------------------------------------------------------------------------- // TKeyOf // -------------------------------------------------------------------------- -// prettier-ignore -export type TKeyOfProperties = Discard extends infer S - ? UnionToTuple<{ [K in keyof S]: TLiteral> }[keyof S]> - : [], undefined> // note: optional properties produce undefined types in tuple result. discard. -// prettier-ignore -export type TKeyOfIndicesArray = UnionToTuple -// prettier-ignore -export type TKeyOfIndices = AssertRest extends infer R ? { - [K in keyof R]: TLiteral> -} : []> -// prettier-ignore -export type TKeyOf = ( - T extends TRecursive ? TKeyOfProperties : - T extends TIntersect ? TKeyOfProperties : - T extends TUnion ? TKeyOfProperties : - T extends TObject ? TKeyOfProperties : - T extends TTuple ? TKeyOfIndices : - T extends TArray ? [TNumber] : - T extends TRecord ? [K] : - [] -) extends infer R ? UnionType.Resolve> : never + // -------------------------------------------------------------------------- // TLiteral // -------------------------------------------------------------------------- @@ -2759,25 +2739,27 @@ export namespace KeyResolver { ? Increment.Next : '0' ) - export type Tuple = ( + export type TupleCollect = ( T extends [infer _, ...infer R extends TSchema[]] - ? Tuple, ...I]> + ? TupleCollect, ...I]> : I ) + export type Tuple = Reverse> + export function Tuple(T: [...T]): Tuple { return ( - T.map((_, index) => index).reverse() + T.map((_, index) => index.toString()) ) as Tuple } // ---------------------------------------------------------------- // Array // ---------------------------------------------------------------- export type Array<_ extends TSchema> = ( - ['number'] + ['[number]'] ) export function Array<_ extends TSchema>(_: _): Array<_> { return ( - ['number'] + ['[number]'] ) } // ---------------------------------------------------------------- @@ -2901,8 +2883,8 @@ export namespace IndexResolver { T extends TTemplateLiteral ? TemplateLiteral : T extends TUnion ? Union : T extends TLiteral ? Literal : - T extends TNumber ? ['number'] : - T extends TInteger ? ['number'] : + T extends TNumber ? ['[number]'] : + T extends TInteger ? ['[number]'] : [] ) export function Resolve(T: T): Resolve { @@ -2910,8 +2892,8 @@ export namespace IndexResolver { 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 } @@ -2998,13 +2980,13 @@ export namespace AccessResolver { // ---------------------------------------------------------------- export type Tuple = ( K extends keyof T ? T[K] : - K extends 'number' ? UnionType.Resolve : + K extends '[number]' ? UnionType.Resolve : TNever ) export function Tuple(T: [...T], K: K): Tuple { return ( K in T ? T[K as number] : - K === 'number' ? UnionType.Resolve(T) : + K === '[number]' ? UnionType.Resolve(T) : Type.Never() ) as Tuple } @@ -3018,7 +3000,7 @@ export namespace AccessResolver { ) export function Array(T: T, K: K): Array { return ( - K === 'number' + K === '[number]' ? T : Type.Never() ) as Array @@ -3098,14 +3080,18 @@ export namespace KeyOfResolver { // ---------------------------------------------------------------- export type Literals = ( T extends [infer L extends TLiteralValue, ...infer R extends TLiteralValue[]] - ? [TLiteral, ...Literals] + ? L extends '[number]' + ? [TNumber, ...Literals] + : [TLiteral, ...Literals] : [] ) export function Literals(T: [...T]): Literals { 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 } diff --git a/test/runtime/type/guard/keyof.ts b/test/runtime/type/guard/keyof.ts index 43a7426d9..d8b24ad74 100644 --- a/test/runtime/type/guard/keyof.ts +++ b/test/runtime/type/guard/keyof.ts @@ -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') }) })