From 35b1bb9ec931d71a71ff12ae32eebcdbad4812b6 Mon Sep 17 00:00:00 2001 From: sinclairzx81 Date: Sun, 23 Apr 2023 13:48:01 +0900 Subject: [PATCH] Revision 0.28.5 (#409) --- package-lock.json | 4 +- package.json | 2 +- src/typebox.ts | 60 +++++++++++++++--------------- test/runtime/type/guard/indexed.ts | 18 +++++++++ test/static/indexed.ts | 14 +++++++ 5 files changed, 66 insertions(+), 32 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4213c74..1ccf314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@sinclair/typebox", - "version": "0.28.4", + "version": "0.28.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@sinclair/typebox", - "version": "0.28.4", + "version": "0.28.5", "license": "MIT", "devDependencies": { "@sinclair/hammer": "^0.17.1", diff --git a/package.json b/package.json index ad4c5c9..a34bb2f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.28.4", + "version": "0.28.5", "description": "JSONSchema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", diff --git a/src/typebox.ts b/src/typebox.ts index d96f99d..21df623 100644 --- a/src/typebox.ts +++ b/src/typebox.ts @@ -337,9 +337,9 @@ export type TIndexKeys = [...TIndexKey>, ...TIndexKeys>] : [] // prettier-ignore -export type TIndex = +export type TIndexFromKeyTuple = TIndexKeys extends infer R ? - T extends TRecursive ? TIndex : + T extends TRecursive ? TIndexFromKeyTuple : T extends TTuple ? UnionType> : T extends TIntersect ? UnionType> : T extends TUnion ? UnionType> : @@ -347,6 +347,14 @@ export type TIndex = T extends TArray ? UnionType> : TNever : TNever +// prettier-ignore +export type TIndex = + [T, K] extends [TTuple, TNumber] ? UnionType> : + [T, K] extends [TArray, TNumber] ? AssertType : + K extends TTemplateLiteral ? TIndexFromKeyTuple> : + K extends TUnion[]> ? TIndexFromKeyTuple> : + K extends TLiteral ? TIndexFromKeyTuple : + TNever // -------------------------------------------------------------------------- // TInteger // -------------------------------------------------------------------------- @@ -679,7 +687,7 @@ export type TTemplateLiteralConst = export type TTemplateLiteralUnion = T extends [infer L, ...infer R] ? `${TTemplateLiteralConst}${TTemplateLiteralUnion, Acc>}` : Acc -export type TTemplateLiteralKeyArray = Assert>, Key[]> +export type TTemplateLiteralKeyTuple = Assert>, Key[]> export interface TTemplateLiteral extends TSchema { [Kind]: 'TemplateLiteral' static: TTemplateLiteralUnion @@ -690,9 +698,12 @@ export interface TTemplateLiteral> = T extends TTuple ? AssertRest : never + +export type TTupleInfer = T extends [infer L, ...infer R] ? [Static, P>, ...TTupleInfer, P>] : [] + export interface TTuple extends TSchema { [Kind]: 'Tuple' - static: { [K in keyof T]: T[K] extends TSchema ? Static : T[K] } + static: TTupleInfer // { [K in keyof T]: T[K] extends TSchema ? Static : T[K] } type: 'array' items?: T additionalItems?: false @@ -709,15 +720,16 @@ export interface TUndefined extends TSchema { typeOf: 'Undefined' } // -------------------------------------------------------------------------- -// TUnionOfLiteral +// TUnionLiteral // -------------------------------------------------------------------------- // prettier-ignore export type TLiteralUnionReduce[]> = T extends [infer L, ...infer R] ? [Assert>['const'], ...TLiteralUnionReduce[]>>] : [] // prettier-ignore -export type TLiteralUnion[]>> = - T extends TUnion ? TLiteralUnionReduce[]>> : [] +export type TUnionLiteral[]>> = + T extends TUnion ? TLiteralUnionReduce[]>> : + [] // -------------------------------------------------------------------------- // TUnion // -------------------------------------------------------------------------- @@ -1045,10 +1057,6 @@ export namespace TypeGuard { export function TLiteralBoolean(schema: unknown): schema is TLiteral { return TKind(schema) && schema[Kind] === 'Literal' && IsOptionalString(schema.$id) && typeof schema.const === 'boolean' } - /** Returns true if the given schema is TUnion[]> */ - export function TLiteralUnion(schema: unknown): schema is TUnion { - return TUnion(schema) && schema.anyOf.every((schema) => TLiteralString(schema) || TLiteralNumber(schema)) - } /** Returns true if the given schema is TLiteral */ export function TLiteral(schema: unknown): schema is TLiteral { return TLiteralString(schema) || TLiteralNumber(schema) || TLiteralBoolean(schema) @@ -1245,6 +1253,10 @@ export namespace TypeGuard { IsOptionalString(schema.$id) ) } + /** Returns true if the given schema is TUnion[]> */ + export function TUnionLiteral(schema: unknown): schema is TUnion { + return TUnion(schema) && schema.anyOf.every((schema) => TLiteralString(schema) || TLiteralNumber(schema)) + } /** Returns true if the given schema is TUnion */ export function TUnion(schema: unknown): schema is TUnion { // prettier-ignore @@ -2019,7 +2031,7 @@ export namespace KeyArrayResolver { /** Resolves an array of string[] keys from the given schema or array type. */ export function Resolve(schema: TSchema | string[]): string[] { if (globalThis.Array.isArray(schema)) return schema - if (TypeGuard.TLiteralUnion(schema)) return schema.anyOf.map((schema) => schema.const.toString()) + if (TypeGuard.TUnionLiteral(schema)) return schema.anyOf.map((schema) => schema.const.toString()) if (TypeGuard.TLiteral(schema)) return [schema.const as string] if (TypeGuard.TTemplateLiteral(schema)) { const expression = TemplateLiteralParser.ParseExact(schema.pattern) @@ -2407,19 +2419,9 @@ export class StandardTypeBuilder extends TypeBuilder { } } /** `[Standard]` Returns indexed property types for the given keys */ - public Index)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndex> + public Index)[]>(schema: T, keys: [...K], options?: SchemaOptions): TIndexFromKeyTuple> /** `[Standard]` Returns indexed property types for the given keys */ - public Index[]>>(schema: T, keys: K, options?: SchemaOptions): TIndex> - /** `[Standard]` Returns indexed property types for the given keys */ - public Index>(schema: T, key: K, options?: SchemaOptions): TIndex - /** `[Standard]` Returns indexed property types for the given keys */ - public Index(schema: T, key: K, options?: SchemaOptions): TIndex> - /** `[Standard]` Returns indexed property types for the given keys */ - public Index(schema: T, key: K, options?: SchemaOptions): UnionType> - /** `[Standard]` Returns indexed property types for the given keys */ - public Index(schema: T, key: K, options?: SchemaOptions): AssertType - /** `[Standard]` Returns indexed property types for the given keys */ - public Index(schema: T, key: K, options?: SchemaOptions): TIndex + public Index(schema: T, key: K, options?: SchemaOptions): TIndex /** `[Standard]` Returns indexed property types for the given keys */ public Index(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { const keys = KeyArrayResolver.Resolve(unresolved) @@ -2513,11 +2515,11 @@ export class StandardTypeBuilder extends TypeBuilder { /** `[Standard]` Creates a mapped type whose keys are omitted from the given type */ public Omit)[]>(schema: T, keys: readonly [...K], options?: SchemaOptions): TOmit /** `[Standard]` Creates a mapped type whose keys are omitted from the given type */ - public Omit[]>>(schema: T, keys: K, options?: SchemaOptions): TOmit[number]> + public Omit[]>>(schema: T, keys: K, options?: SchemaOptions): TOmit[number]> /** `[Standard]` Creates a mapped type whose keys are omitted from the given type */ public Omit>(schema: T, key: K, options?: SchemaOptions): TOmit /** `[Standard]` Creates a mapped type whose keys are omitted from the given type */ - public Omit(schema: T, key: K, options?: SchemaOptions): TOmit[number]> + public Omit(schema: T, key: K, options?: SchemaOptions): TOmit[number]> /** `[Standard]` Creates a mapped type whose keys are omitted from the given type */ public Omit(schema: T, key: K, options?: SchemaOptions): TOmit public Omit(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { @@ -2555,11 +2557,11 @@ export class StandardTypeBuilder extends TypeBuilder { /** `[Standard]` Creates a mapped type whose keys are picked from the given type */ public Pick)[]>(schema: T, keys: readonly [...K], options?: SchemaOptions): TPick /** `[Standard]` Creates a mapped type whose keys are picked from the given type */ - public Pick[]>>(schema: T, keys: K, options?: SchemaOptions): TPick[number]> + public Pick[]>>(schema: T, keys: K, options?: SchemaOptions): TPick[number]> /** `[Standard]` Creates a mapped type whose keys are picked from the given type */ public Pick>(schema: T, key: K, options?: SchemaOptions): TPick /** `[Standard]` Creates a mapped type whose keys are picked from the given type */ - public Pick(schema: T, key: K, options?: SchemaOptions): TPick[number]> + public Pick(schema: T, key: K, options?: SchemaOptions): TPick[number]> /** `[Standard]` Creates a mapped type whose keys are picked from the given type */ public Pick(schema: T, key: K, options?: SchemaOptions): TPick public Pick(schema: TSchema, unresolved: any, options: SchemaOptions = {}): any { @@ -2596,7 +2598,7 @@ export class StandardTypeBuilder extends TypeBuilder { : this.Create({ ...options, [Kind]: 'Record', type: 'object', patternProperties: { [key.pattern]: TypeClone.Clone(schema, {}) }}) } else if (TypeGuard.TUnion(key)) { const union = UnionResolver.Resolve(key) - if (TypeGuard.TLiteralUnion(union)) { + if (TypeGuard.TUnionLiteral(union)) { const properties = union.anyOf.reduce((acc: any, literal: any) => ({ ...acc, [literal.const]: TypeClone.Clone(schema, {}) }), {} as TProperties) return this.Object(properties, { ...options, [Hint]: 'Record' }) } else throw Error('TypeBuilder: Record key of type union contains non-literal types') diff --git a/test/runtime/type/guard/indexed.ts b/test/runtime/type/guard/indexed.ts index f648ba7..84683b5 100644 --- a/test/runtime/type/guard/indexed.ts +++ b/test/runtime/type/guard/indexed.ts @@ -151,4 +151,22 @@ describe('type/guard/TIndex', () => { Assert.isTrue(TypeGuard.TNumber(I.anyOf[0])) Assert.isTrue(TypeGuard.TBoolean(I.anyOf[1])) }) + it('Should Index 20', () => { + const T = Type.Object({ + 0: Type.Number(), + 1: Type.String(), + 2: Type.Boolean(), + }) + const I = Type.Index(T, Type.BigInt()) + Assert.isTrue(TypeGuard.TNever(I)) + }) + it('Should Index 21', () => { + const T = Type.Object({ + 0: Type.Number(), + 1: Type.String(), + 2: Type.Boolean(), + }) + const I = Type.Index(T, Type.Object({})) + Assert.isTrue(TypeGuard.TNever(I)) + }) }) diff --git a/test/static/indexed.ts b/test/static/indexed.ts index 01ee875..629582b 100644 --- a/test/static/indexed.ts +++ b/test/static/indexed.ts @@ -48,3 +48,17 @@ import { Type, Static } from '@sinclair/typebox' Expect(R).ToInfer() } +{ + const A = Type.Object({}) + + const R = Type.Index(A, Type.BigInt()) // Support Overload + + Expect(R).ToInfer() +} +{ + const A = Type.Array(Type.Number()) + + const R = Type.Index(A, Type.BigInt()) // Support Overload + + Expect(R).ToInfer() +}