From cc068713a5d6bd060617b01de1f30c3dee6f266d Mon Sep 17 00:00:00 2001 From: sinclairzx81 Date: Sun, 21 Jan 2024 03:23:24 +0900 Subject: [PATCH] Revision 0.32.11 (#738) * Optimize Extract and Exclude * Version --- package-lock.json | 4 +- package.json | 2 +- src/index.ts | 6 ++- .../exclude/exclude-from-mapped-result.ts | 14 +++---- .../exclude/exclude-from-template-literal.ts | 39 +++++++++++++++++++ src/type/exclude/exclude.ts | 37 ++++++++---------- src/type/exclude/index.ts | 1 + .../extract/extract-from-mapped-result.ts | 14 +++---- .../extract/extract-from-template-literal.ts | 39 +++++++++++++++++++ src/type/extract/extract.ts | 34 ++++++++-------- src/type/extract/index.ts | 1 + src/type/template-literal/union.ts | 22 ++++++++--- src/type/type/json.ts | 8 +++- test/static/exclude.ts | 15 +++++++ test/static/extract.ts | 17 ++++++++ 15 files changed, 188 insertions(+), 65 deletions(-) create mode 100644 src/type/exclude/exclude-from-template-literal.ts create mode 100644 src/type/extract/extract-from-template-literal.ts diff --git a/package-lock.json b/package-lock.json index 87202da08..292708f95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@sinclair/typebox", - "version": "0.32.10", + "version": "0.32.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@sinclair/typebox", - "version": "0.32.10", + "version": "0.32.11", "license": "MIT", "devDependencies": { "@arethetypeswrong/cli": "^0.13.2", diff --git a/package.json b/package.json index 0f1575d2e..26107da3d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@sinclair/typebox", - "version": "0.32.10", + "version": "0.32.11", "description": "Json Schema Type Builder with Static Type Resolution for TypeScript", "keywords": [ "typescript", diff --git a/src/index.ts b/src/index.ts index cfcd03abe..2108648d5 100644 --- a/src/index.ts +++ b/src/index.ts @@ -79,9 +79,9 @@ export { ConstructorParameters, type TConstructorParameters } from './type/const export { Date, type TDate, type DateOptions } from './type/date/index' export { Deref, type TDeref } from './type/deref/index' export { Enum, type TEnum } from './type/enum/index' -export { Exclude, type TExclude, type TExcludeFromMappedResult } from './type/exclude/index' +export { Exclude, type TExclude, type TExcludeFromMappedResult, type TExcludeFromTemplateLiteral } from './type/exclude/index' export { Extends, ExtendsCheck, ExtendsResult, ExtendsUndefinedCheck, type TExtends, type ExtendsFromMappedResult, type ExtendsFromMappedKey } from './type/extends/index' -export { Extract, type TExtract, type TExtractFromMappedResult } from './type/extract/index' +export { Extract, type TExtract, type TExtractFromMappedResult, type TExtractFromTemplateLiteral } from './type/extract/index' export { Function, type TFunction } from './type/function/index' export { Index, @@ -136,6 +136,7 @@ export { TemplateLiteralGenerate, TemplateLiteralParse, TemplateLiteralParseExact, + TemplateLiteralToUnion, IsTemplateLiteralFinite, TemplateLiteralExpressionGenerate, IsTemplateLiteralExpressionFinite, @@ -143,6 +144,7 @@ export { type TTemplateLiteralSyntax, type TTemplateLiteralGenerate, type TTemplateLiteralKind, + type TTemplateLiteralToUnion, type TIsTemplateLiteralFinite, } from './type/template-literal/index' export { Transform, TransformDecodeBuilder, TransformEncodeBuilder, type TTransform, type TransformOptions, type TransformFunction } from './type/transform/index' diff --git a/src/type/exclude/exclude-from-mapped-result.ts b/src/type/exclude/exclude-from-mapped-result.ts index a8934686f..3fe927fde 100644 --- a/src/type/exclude/exclude-from-mapped-result.ts +++ b/src/type/exclude/exclude-from-mapped-result.ts @@ -26,7 +26,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import type { TSchema, SchemaOptions } from '../schema/index' +import type { TSchema } from '../schema/index' import type { TProperties } from '../object/index' import { MappedResult, type TMappedResult } from '../mapped/index' import { Exclude, type TExclude } from './exclude' @@ -45,9 +45,9 @@ type TFromProperties< function FromProperties< P extends TProperties, T extends TSchema ->(P: P, U: T, options: SchemaOptions): TFromProperties { +>(P: P, U: T): TFromProperties { return globalThis.Object.getOwnPropertyNames(P).reduce((Acc, K2) => { - return {...Acc, [K2]: Exclude(P[K2], U, options) } + return {...Acc, [K2]: Exclude(P[K2], U) } }, {}) as TFromProperties } // ------------------------------------------------------------------ @@ -64,8 +64,8 @@ type TFromMappedResult< function FromMappedResult< R extends TMappedResult, T extends TSchema ->(R: R, T: T, options: SchemaOptions): TFromMappedResult { - return FromProperties(R.properties, T, options) as TFromMappedResult +>(R: R, T: T): TFromMappedResult { + return FromProperties(R.properties, T) as TFromMappedResult } // ------------------------------------------------------------------ // ExcludeFromMappedResult @@ -83,7 +83,7 @@ export function ExcludeFromMappedResult< R extends TMappedResult, T extends TSchema, P extends TProperties = TFromMappedResult ->(R: R, T: T, options: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(R, T, options) as unknown as P +>(R: R, T: T): TMappedResult

{ + const P = FromMappedResult(R, T) as unknown as P return MappedResult(P) } diff --git a/src/type/exclude/exclude-from-template-literal.ts b/src/type/exclude/exclude-from-template-literal.ts new file mode 100644 index 000000000..707a6c254 --- /dev/null +++ b/src/type/exclude/exclude-from-template-literal.ts @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { TExclude, Exclude } from './exclude' +import { TemplateLiteralToUnion, type TTemplateLiteral, type TTemplateLiteralToUnion } from '../template-literal/index' + +// prettier-ignore +export type TExcludeFromTemplateLiteral = ( + TExclude, R> +) +export function ExcludeFromTemplateLiteral(L: L, R: R): TExcludeFromTemplateLiteral { + return Exclude(TemplateLiteralToUnion(L), R) as never +} diff --git a/src/type/exclude/exclude.ts b/src/type/exclude/exclude.ts index d82bdf33a..021caf156 100644 --- a/src/type/exclude/exclude.ts +++ b/src/type/exclude/exclude.ts @@ -27,32 +27,23 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import type { TSchema, SchemaOptions } from '../schema/index' -import type { UnionToTuple, AssertRest, AssertType, Assert } from '../helpers/index' +import type { UnionToTuple, AssertRest, AssertType } from '../helpers/index' import type { TMappedResult } from '../mapped/index' -import { TemplateLiteralToUnion, type TTemplateLiteral } from '../template-literal/index' +import { type TTemplateLiteral } from '../template-literal/index' import { Union, type TUnion } from '../union/index' import { Never, type TNever } from '../never/index' -import { type TLiteral } from '../literal/index' import { type Static } from '../static/index' import { type TUnionEvaluated } from '../union/index' import { ExtendsCheck, ExtendsResult } from '../extends/index' import { CloneType } from '../clone/type' import { ExcludeFromMappedResult, type TExcludeFromMappedResult } from './exclude-from-mapped-result' +import { ExcludeFromTemplateLiteral, type TExcludeFromTemplateLiteral } from './exclude-from-template-literal' // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ import { IsMappedResult, IsTemplateLiteral, IsUnion } from '../guard/type' // ------------------------------------------------------------------ -// ExcludeTemplateLiteral -// ------------------------------------------------------------------ -// prettier-ignore -type TExcludeTemplateLiteralResult = TUnionEvaluated }[T]>>> -// prettier-ignore -type TExcludeTemplateLiteral = ( - Exclude, Static> extends infer S ? TExcludeTemplateLiteralResult> : never -) -// ------------------------------------------------------------------ // ExcludeRest // ------------------------------------------------------------------ // prettier-ignore @@ -69,19 +60,23 @@ function ExcludeRest(L: [...L], R: R) { // ------------------------------------------------------------------ // prettier-ignore export type TExclude = ( - L extends TMappedResult ? TExcludeFromMappedResult : - L extends TTemplateLiteral ? TExcludeTemplateLiteral : L extends TUnion ? TExcludeRest : L extends R ? TNever : L ) /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ -export function Exclude(L: L, R: R, options: SchemaOptions = {}): TExclude { +export function Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExcludeFromMappedResult +/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ +export function Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExcludeFromTemplateLiteral +/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ +export function Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExclude +/** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ +export function Exclude(L: TSchema, R: TSchema, options: SchemaOptions = {}): any { + // overloads + if (IsTemplateLiteral(L)) return CloneType(ExcludeFromTemplateLiteral(L, R), options) + if (IsMappedResult(L)) return CloneType(ExcludeFromMappedResult(L, R), options) // prettier-ignore - return CloneType(( - IsMappedResult(L) ? ExcludeFromMappedResult(L, R, options) : - IsTemplateLiteral(L) ? Exclude(TemplateLiteralToUnion(L), R) : - IsTemplateLiteral(R) ? Exclude(L, TemplateLiteralToUnion(R)) : - IsUnion(L) ? ExcludeRest(L.anyOf, R) : + return CloneType( + IsUnion(L) ? ExcludeRest(L.anyOf, R) : ExtendsCheck(L, R) !== ExtendsResult.False ? Never() : L - ), options) as never + , options) } diff --git a/src/type/exclude/index.ts b/src/type/exclude/index.ts index 335e87a04..610ff43a2 100644 --- a/src/type/exclude/index.ts +++ b/src/type/exclude/index.ts @@ -27,4 +27,5 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ export * from './exclude-from-mapped-result' +export * from './exclude-from-template-literal' export * from './exclude' diff --git a/src/type/extract/extract-from-mapped-result.ts b/src/type/extract/extract-from-mapped-result.ts index c21ed3567..65d244162 100644 --- a/src/type/extract/extract-from-mapped-result.ts +++ b/src/type/extract/extract-from-mapped-result.ts @@ -26,7 +26,7 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ -import type { TSchema, SchemaOptions } from '../schema/index' +import type { TSchema } from '../schema/index' import type { TProperties } from '../object/index' import { MappedResult, type TMappedResult } from '../mapped/index' import { Extract, type TExtract } from './extract' @@ -45,9 +45,9 @@ type TFromProperties< function FromProperties< P extends TProperties, T extends TSchema ->(P: P, T: T, options: SchemaOptions): TFromProperties { +>(P: P, T: T): TFromProperties { return globalThis.Object.getOwnPropertyNames(P).reduce((Acc, K2) => { - return {...Acc, [K2]: Extract(P[K2], T, options) } + return {...Acc, [K2]: Extract(P[K2], T) } }, {}) as TFromProperties } // ------------------------------------------------------------------ @@ -64,8 +64,8 @@ type TFromMappedResult< function FromMappedResult< R extends TMappedResult, T extends TSchema ->(R: R, T: T, options: SchemaOptions): TFromMappedResult { - return FromProperties(R.properties, T, options) as TFromMappedResult +>(R: R, T: T): TFromMappedResult { + return FromProperties(R.properties, T) as TFromMappedResult } // ------------------------------------------------------------------ // ExtractFromMappedResult @@ -83,7 +83,7 @@ export function ExtractFromMappedResult< R extends TMappedResult, T extends TSchema, P extends TProperties = TFromMappedResult ->(R: R, T: T, options: SchemaOptions): TMappedResult

{ - const P = FromMappedResult(R, T, options) as unknown as P +>(R: R, T: T): TMappedResult

{ + const P = FromMappedResult(R, T) as unknown as P return MappedResult(P) } diff --git a/src/type/extract/extract-from-template-literal.ts b/src/type/extract/extract-from-template-literal.ts new file mode 100644 index 000000000..82cc52dd9 --- /dev/null +++ b/src/type/extract/extract-from-template-literal.ts @@ -0,0 +1,39 @@ +/*-------------------------------------------------------------------------- + +@sinclair/typebox/type + +The MIT License (MIT) + +Copyright (c) 2017-2024 Haydn Paterson (sinclair) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +---------------------------------------------------------------------------*/ + +import type { TSchema } from '../schema/index' +import { Extract, type TExtract } from './extract' +import { TemplateLiteralToUnion, type TTemplateLiteral, type TTemplateLiteralToUnion } from '../template-literal/index' + +// prettier-ignore +export type TExtractFromTemplateLiteral = ( + TExtract, R> +) +export function ExtractFromTemplateLiteral(L: L, R: R): TExtractFromTemplateLiteral { + return Extract(TemplateLiteralToUnion(L), R) as never +} diff --git a/src/type/extract/extract.ts b/src/type/extract/extract.ts index a1f6f4d54..40d7e2d3d 100644 --- a/src/type/extract/extract.ts +++ b/src/type/extract/extract.ts @@ -27,29 +27,23 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ import type { TSchema, SchemaOptions } from '../schema/index' -import type { Assert, AssertRest, AssertType, UnionToTuple } from '../helpers/index' +import type { AssertRest, AssertType, UnionToTuple } from '../helpers/index' import type { TMappedResult } from '../mapped/index' -import { TemplateLiteralToUnion, type TTemplateLiteral } from '../template-literal/index' -import { type TLiteral } from '../literal/index' import { Union, type TUnion } from '../union/index' import { type Static } from '../static/index' import { Never, type TNever } from '../never/index' import { type TUnionEvaluated } from '../union/index' +import { type TTemplateLiteral } from '../template-literal/index' import { ExtendsCheck, ExtendsResult } from '../extends/index' import { CloneType } from '../clone/type' import { ExtractFromMappedResult, type TExtractFromMappedResult } from './extract-from-mapped-result' +import { ExtractFromTemplateLiteral, type TExtractFromTemplateLiteral } from './extract-from-template-literal' // ------------------------------------------------------------------ // TypeGuard // ------------------------------------------------------------------ import { IsMappedResult, IsTemplateLiteral, IsUnion } from '../guard/type' -// ------------------------------------------------------------------ -// ExtractTemplateLiteral -// ------------------------------------------------------------------ -// prettier-ignore -type TExtractTemplateLiteralResult = TUnionEvaluated }[T]>>> -// prettier-ignore -type TExtractTemplateLiteral = Extract, Static> extends infer S ? TExtractTemplateLiteralResult> : never + // ------------------------------------------------------------------ // ExtractRest // ------------------------------------------------------------------ @@ -67,19 +61,23 @@ function ExtractRest(L: [...L], R: R) { // ------------------------------------------------------------------ // prettier-ignore export type TExtract = ( - L extends TMappedResult ? TExtractFromMappedResult : - L extends TTemplateLiteral ? TExtractTemplateLiteral : L extends TUnion ? TExtractRest : L extends U ? L : TNever ) /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ -export function Extract(L: L, R: R, options: SchemaOptions = {}): TExtract { +export function Extract(type: L, union: R, options?: SchemaOptions): TExtractFromMappedResult +/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ +export function Extract(type: L, union: R, options?: SchemaOptions): TExtractFromTemplateLiteral +/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ +export function Extract(type: L, union: R, options?: SchemaOptions): TExtract +/** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ +export function Extract(L: TSchema, R: TSchema, options: SchemaOptions = {}): any { + // overloads + if (IsTemplateLiteral(L)) return CloneType(ExtractFromTemplateLiteral(L, R), options) + if (IsMappedResult(L)) return CloneType(ExtractFromMappedResult(L, R), options) // prettier-ignore - return CloneType(( - IsMappedResult(L) ? ExtractFromMappedResult(L, R, options) : - IsTemplateLiteral(L) ? Extract(TemplateLiteralToUnion(L), R) : - IsTemplateLiteral(R) ? Extract(L, TemplateLiteralToUnion(R) as any) : + return CloneType( IsUnion(L) ? ExtractRest(L.anyOf, R) : ExtendsCheck(L, R) !== ExtendsResult.False ? L : Never() - ), options) as never + , options) } diff --git a/src/type/extract/index.ts b/src/type/extract/index.ts index baa79009e..38bc0a813 100644 --- a/src/type/extract/index.ts +++ b/src/type/extract/index.ts @@ -27,4 +27,5 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ export * from './extract-from-mapped-result' +export * from './extract-from-template-literal' export * from './extract' diff --git a/src/type/template-literal/union.ts b/src/type/template-literal/union.ts index a5a1f9240..dba883805 100644 --- a/src/type/template-literal/union.ts +++ b/src/type/template-literal/union.ts @@ -26,19 +26,31 @@ THE SOFTWARE. ---------------------------------------------------------------------------*/ +import type { Static } from '../static/index' import type { TTemplateLiteral } from './template-literal' -import { Union, type TUnion } from '../union/index' +import type { UnionToTuple } from '../helpers/index' +import { UnionEvaluated, type TUnionEvaluated } from '../union/index' import { Literal, type TLiteral } from '../literal/index' -import { type TString } from '../string/index' -import { type TNever } from '../never/index' import { TemplateLiteralGenerate } from './generate' // ------------------------------------------------------------------ // TemplateLiteralToUnion // ------------------------------------------------------------------ +// prettier-ignore +export type TTemplateLiteralToUnionLiteralArray = ( + T extends [infer L extends string, ...infer R extends string[]] + ? TTemplateLiteralToUnionLiteralArray]> + : Acc +) +// prettier-ignore +export type TTemplateLiteralToUnion< + T extends TTemplateLiteral, + U extends string[] = UnionToTuple> +> = TUnionEvaluated> + /** Returns a Union from the given TemplateLiteral */ -export function TemplateLiteralToUnion(schema: TTemplateLiteral): TNever | TString | TUnion { +export function TemplateLiteralToUnion(schema: TTemplateLiteral): TTemplateLiteralToUnion { const R = TemplateLiteralGenerate(schema) as string[] const L = R.map((S) => Literal(S)) - return Union(L) + return UnionEvaluated(L) } diff --git a/src/type/type/json.ts b/src/type/type/json.ts index 772ff0ee9..af79c93a4 100644 --- a/src/type/type/json.ts +++ b/src/type/type/json.ts @@ -33,9 +33,9 @@ import { Composite, type TComposite } from '../composite/index' import { Const, type TConst } from '../const/index' import { Deref, type TDeref } from '../deref/index' import { Enum, type TEnum, type TEnumKey, type TEnumValue } from '../enum/index' -import { Exclude, type TExclude, type TExcludeFromMappedResult } from '../exclude/index' +import { Exclude, type TExclude, type TExcludeFromMappedResult, type TExcludeFromTemplateLiteral } from '../exclude/index' import { Extends, type TExtends, type TExtendsFromMappedKey, type TExtendsFromMappedResult } from '../extends/index' -import { Extract, type TExtract, type TExtractFromMappedResult } from '../extract/index' +import { Extract, type TExtract, type TExtractFromMappedResult, type TExtractFromTemplateLiteral } from '../extract/index' import { Index, TIndex, type TIndexPropertyKeys, type TIndexFromMappedKey, type TIndexFromMappedResult } from '../indexed/index' import { Integer, type IntegerOptions, type TInteger } from '../integer/index' import { Intersect, type IntersectOptions } from '../intersect/index' @@ -148,6 +148,8 @@ export class JsonTypeBuilder { /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ public Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExcludeFromMappedResult /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ + public Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExcludeFromTemplateLiteral + /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ public Exclude(unionType: L, excludedMembers: R, options?: SchemaOptions): TExclude /** `[Json]` Constructs a type by excluding from unionType all union members that are assignable to excludedMembers */ public Exclude(unionType: TSchema, excludedMembers: TSchema, options: SchemaOptions = {}): any { @@ -166,6 +168,8 @@ export class JsonTypeBuilder { /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ public Extract(type: L, union: R, options?: SchemaOptions): TExtractFromMappedResult /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ + public Extract(type: L, union: R, options?: SchemaOptions): TExtractFromTemplateLiteral + /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ public Extract(type: L, union: R, options?: SchemaOptions): TExtract /** `[Json]` Constructs a type by extracting from type all union members that are assignable to union */ public Extract(type: TSchema, union: TSchema, options: SchemaOptions = {}): any { diff --git a/test/static/exclude.ts b/test/static/exclude.ts index 14e1a5104..a63c6c2f4 100644 --- a/test/static/exclude.ts +++ b/test/static/exclude.ts @@ -82,3 +82,18 @@ import { Expect } from './assert' const T = Type.Exclude(A, B) Expect(T).ToStatic<'C' | 'B'>() } +// https://github.com/sinclairzx81/typebox/issues/737 +{ + const U = Type.Union([Type.Literal('A'), Type.Literal('B')]) + const T = Type.Object({ + type: Type.Exclude(U, Type.Literal('A')), + }) + Expect(T).ToStatic<{ type: 'B' }>() +} +{ + const U = Type.Union([Type.Literal('A'), Type.Literal('B'), Type.Literal('C')]) + const T = Type.Object({ + type: Type.Exclude(U, Type.Literal('A')), + }) + Expect(T).ToStatic<{ type: 'B' | 'C' }>() +} diff --git a/test/static/extract.ts b/test/static/extract.ts index 0ed6a2a96..b9e621e95 100644 --- a/test/static/extract.ts +++ b/test/static/extract.ts @@ -81,3 +81,20 @@ import { Expect } from './assert' const T = Type.Extract(A, B) Expect(T).ToStatic<'A'>() } +// ------------------------------------------------------------------------ +// Nested (Inference Test) +// ------------------------------------------------------------------------ +{ + const U = Type.Union([Type.Literal('A'), Type.Literal('B')]) + const T = Type.Object({ + type: Type.Extract(U, Type.Literal('A')), + }) + Expect(T).ToStatic<{ type: 'A' }>() +} +{ + const U = Type.Union([Type.Literal('A'), Type.Literal('B'), Type.Literal('C')]) + const T = Type.Object({ + type: Type.Extract(U, Type.Union([Type.Literal('A'), Type.Literal('B')])), + }) + Expect(T).ToStatic<{ type: 'A' | 'B' }>() +}