Skip to content

Commit 97f80db

Browse files
committed
Version 1.0.69 (#1493)
* Optimize Union Evaluation for Distinct Sets * ChangeLog * Version
1 parent 0257d8a commit 97f80db

14 files changed

Lines changed: 286 additions & 21 deletions

File tree

changelog/1.0.0.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
---
44

55
### Version Updates
6+
- [Revision 1.0.69](https://github.com/sinclairzx81/typebox/pull/1493)
7+
- Optimize Union Evaluation for Distinct Sets
68
- [Revision 1.0.68](https://github.com/sinclairzx81/typebox/pull/1492)
79
- Export Compile as Default Function
810
- [Revision 1.0.67](https://github.com/sinclairzx81/typebox/pull/1491)

example/javascript/date.ts

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
/*--------------------------------------------------------------------------
2+
3+
TypeBox
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2017-2025 Haydn Paterson
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in
17+
all copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
THE SOFTWARE.
26+
27+
---------------------------------------------------------------------------*/
28+
29+
import Type from 'typebox'
30+
31+
// ------------------------------------------------------------------
32+
// Factory
33+
// ------------------------------------------------------------------
34+
export const Date = () => Type.Object({
35+
[Symbol.toPrimitive]: Type.Never(),
36+
/** Returns a string representation of a date. The format of the string depends on the locale. */
37+
toString: Type.Function([], Type.String()),
38+
/** Returns a date as a string value. */
39+
toDateString: Type.Function([], Type.String()),
40+
/** Returns a time as a string value. */
41+
toTimeString: Type.Function([], Type.String()),
42+
/** Returns a value as a string value appropriate to the host environment's current locale. */
43+
toLocaleString: Type.Function([], Type.String()),
44+
/** Returns a date as a string value appropriate to the host environment's current locale. */
45+
toLocaleDateString: Type.Function([], Type.String()),
46+
/** Returns a time as a string value appropriate to the host environment's current locale. */
47+
toLocaleTimeString: Type.Function([], Type.String()),
48+
/** Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC. */
49+
valueOf: Type.Function([], Type.Number()),
50+
/** Returns the stored time value in milliseconds since midnight, January 1, 1970 UTC. */
51+
getTime: Type.Function([], Type.Number()),
52+
/** Gets the year, using local time. */
53+
getFullYear: Type.Function([], Type.Number()),
54+
/** Gets the year using Universal Coordinated Time (UTC). */
55+
getUTCFullYear: Type.Function([], Type.Number()),
56+
/** Gets the month, using local time. */
57+
getMonth: Type.Function([], Type.Number()),
58+
/** Gets the month of a Date object using Universal Coordinated Time (UTC). */
59+
getUTCMonth: Type.Function([], Type.Number()),
60+
/** Gets the day-of-the-month, using local time. */
61+
getDate: Type.Function([], Type.Number()),
62+
/** Gets the day-of-the-month, using Universal Coordinated Time (UTC). */
63+
getUTCDate: Type.Function([], Type.Number()),
64+
/** Gets the day of the week, using local time. */
65+
getDay: Type.Function([], Type.Number()),
66+
/** Gets the day of the week using Universal Coordinated Time (UTC). */
67+
getUTCDay: Type.Function([], Type.Number()),
68+
/** Gets the hours in a date, using local time. */
69+
getHours: Type.Function([], Type.Number()),
70+
/** Gets the hours value in a Date object using Universal Coordinated Time (UTC). */
71+
getUTCHours: Type.Function([], Type.Number()),
72+
/** Gets the minutes of a Date object, using local time. */
73+
getMinutes: Type.Function([], Type.Number()),
74+
/** Gets the minutes of a Date object using Universal Coordinated Time (UTC). */
75+
getUTCMinutes: Type.Function([], Type.Number()),
76+
/** Gets the seconds of a Date object, using local time. */
77+
getSeconds: Type.Function([], Type.Number()),
78+
/** Gets the seconds of a Date object using Universal Coordinated Time (UTC). */
79+
getUTCSeconds: Type.Function([], Type.Number()),
80+
/** Gets the milliseconds of a Date, using local time. */
81+
getMilliseconds: Type.Function([], Type.Number()),
82+
/** Gets the milliseconds of a Date object using Universal Coordinated Time (UTC). */
83+
getUTCMilliseconds: Type.Function([], Type.Number()),
84+
/** Gets the difference in minutes between Universal Coordinated Time (UTC) and the time on the local computer. */
85+
getTimezoneOffset: Type.Function([], Type.Number()),
86+
/**
87+
* Sets the date and time value in the Date object.
88+
* @param time A numeric value representing the number of elapsed milliseconds since midnight, January 1, 1970 GMT.
89+
*/
90+
setTime: Type.Function([Type.Number()], Type.Number()),
91+
/**
92+
* Sets the milliseconds value in the Date object using local time.
93+
* @param ms A numeric value equal to the millisecond value.
94+
*/
95+
setMilliseconds: Type.Function([Type.Number()], Type.Number()),
96+
/**
97+
* Sets the milliseconds value in the Date object using Universal Coordinated Time (UTC).
98+
* @param ms A numeric value equal to the millisecond value.
99+
*/
100+
setUTCMilliseconds: Type.Function([Type.Number()], Type.Number()),
101+
/**
102+
* Sets the seconds value in the Date object using local time.
103+
* @param sec A numeric value equal to the seconds value.
104+
* @param ms A numeric value equal to the milliseconds value.
105+
*/
106+
setSeconds: Type.Function([Type.Number(), Type.Optional(Type.Number())], Type.Number()),
107+
/**
108+
* Sets the seconds value in the Date object using Universal Coordinated Time (UTC).
109+
* @param sec A numeric value equal to the seconds value.
110+
* @param ms A numeric value equal to the milliseconds value.
111+
*/
112+
setUTCSeconds: Type.Function([Type.Number(), Type.Optional(Type.Number())], Type.Number()),
113+
/**
114+
* Sets the minutes value in the Date object using local time.
115+
* @param min A numeric value equal to the minutes value.
116+
* @param sec A numeric value equal to the seconds value.
117+
* @param ms A numeric value equal to the milliseconds value.
118+
*/
119+
setMinutes: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
120+
/**
121+
* Sets the minutes value in the Date object using Universal Coordinated Time (UTC).
122+
* @param min A numeric value equal to the minutes value.
123+
* @param sec A numeric value equal to the seconds value.
124+
* @param ms A numeric value equal to the milliseconds value.
125+
*/
126+
setUTCMinutes: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
127+
/**
128+
* Sets the hour value in the Date object using local time.
129+
* @param hours A numeric value equal to the hours value.
130+
* @param min A numeric value equal to the minutes value.
131+
* @param sec A numeric value equal to the seconds value.
132+
* @param ms A numeric value equal to the milliseconds value.
133+
*/
134+
setHours: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
135+
/**
136+
* Sets the hours value in the Date object using Universal Coordinated Time (UTC).
137+
* @param hours A numeric value equal to the hours value.
138+
* @param min A numeric value equal to the minutes value.
139+
* @param sec A numeric value equal to the seconds value.
140+
* @param ms A numeric value equal to the milliseconds value.
141+
*/
142+
setUTCHours: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
143+
/**
144+
* Sets the numeric day-of-the-month value of the Date object using local time.
145+
* @param date A numeric value equal to the day of the month.
146+
*/
147+
setDate: Type.Function([Type.Number()], Type.Number()),
148+
/**
149+
* Sets the numeric day of the month in the Date object using Universal Coordinated Time (UTC).
150+
* @param date A numeric value equal to the day of the month.
151+
*/
152+
setUTCDate: Type.Function([Type.Number()], Type.Number()),
153+
/**
154+
* Sets the month value in the Date object using local time.
155+
* @param month A numeric value equal to the month. The value for January is 0, and other month values follow consecutively.
156+
* @param date A numeric value representing the day of the month. If this value is not supplied, the value from a call to the getDate method is used.
157+
*/
158+
setMonth: Type.Function([Type.Number(), Type.Optional(Type.Number())], Type.Number()),
159+
/**
160+
* Sets the month value in the Date object using Universal Coordinated Time (UTC).
161+
* @param month A numeric value equal to the month. The value for January is 0, and other month values follow consecutively.
162+
* @param date A numeric value representing the day of the month. If it is not supplied, the value from a call to the getUTCDate method is used.
163+
*/
164+
setUTCMonth: Type.Function([Type.Number(), Type.Optional(Type.Number())], Type.Number()),
165+
/**
166+
* Sets the year of the Date object using local time.
167+
* @param year A numeric value for the year.
168+
* @param month A zero-based numeric value for the month (0 for January, 11 for December). Must be specified if numDate is specified.
169+
* @param date A numeric value equal for the day of the month.
170+
*/
171+
setFullYear: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
172+
/**
173+
* Sets the year value in the Date object using Universal Coordinated Time (UTC).
174+
* @param year A numeric value equal to the year.
175+
* @param month A numeric value equal to the month. The value for January is 0, and other month values follow consecutively. Must be supplied if numDate is supplied.
176+
* @param date A numeric value equal to the day of the month.
177+
*/
178+
setUTCFullYear: Type.Function([Type.Number(), Type.Optional(Type.Number()), Type.Optional(Type.Number())], Type.Number()),
179+
/** Returns a date converted to a string using Universal Coordinated Time (UTC). */
180+
toUTCString: Type.Function([], Type.String()),
181+
/** Returns a date as a string value in ISO format. */
182+
toISOString: Type.Function([], Type.String()),
183+
/** Used by the JSON.stringify method to enable the transformation of an object's data for JavaScript Object Notation (JSON) serialization. */
184+
toJSON: Type.Function([Type.Optional(Type.String())], Type.String()),
185+
})

src/system/memory/discard.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ THE SOFTWARE.
2828

2929
// deno-fmt-ignore-file
3030

31-
import { Metrics } from "./metrics.ts"
31+
import { Metrics } from './metrics.ts'
3232
import { Clone } from './clone.ts'
3333

3434
type ObjectLike = Record<PropertyKey, any>

src/system/memory/update.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ THE SOFTWARE.
2929
// deno-fmt-ignore-file
3030

3131
import { Settings } from '../settings/index.ts'
32-
import { Metrics } from "./metrics.ts"
32+
import { Metrics } from './metrics.ts'
3333
import { Clone } from './clone.ts'
3434

3535
// deno-lint-ignore no-explicit-any

src/type/engine/evaluate/distribute.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,9 @@ import { type TObject, IsObject } from '../../types/object.ts'
3737
import { type TTuple, IsTuple } from '../../types/tuple.ts'
3838
import { type TComposite, Composite } from './composite.ts'
3939
import { type TNarrow, Narrow } from './narrow.ts'
40-
import { type TEvaluateType, EvaluateType } from "./evaluate.ts"
40+
import { type TEvaluateType, EvaluateType } from './evaluate.ts'
4141

42-
import { type TEvaluateIntersect, EvaluateIntersect } from "./evaluate.ts"
42+
import { type TEvaluateIntersect, EvaluateIntersect } from './evaluate.ts'
4343

4444
// -----------------------------------------------------------------------------------------
4545
// CanDistribute

src/type/engine/evaluate/evaluate.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ THE SOFTWARE.
2828

2929
// deno-fmt-ignore-file
3030

31+
import { Guard } from '../../../guard/index.ts'
3132
import { type TSchema } from '../../types/schema.ts'
3233
import { type TIntersect, IsIntersect } from '../../types/intersect.ts'
33-
import { type TUnion, IsUnion } from '../../types/union.ts'
3434
import { type TDistribute, Distribute } from './distribute.ts'
3535
import { type TBroaden, Broaden } from './broaden.ts'
36+
import { type TUnion, Union, IsUnion } from '../../types/union.ts'
37+
import { type TNever, Never } from '../../types/never.ts'
3638

3739
// ------------------------------------------------------------------
3840
// EvaluateIntersect
@@ -73,3 +75,27 @@ export function EvaluateType<Type extends TSchema>(type: Type): TEvaluateType<Ty
7375
type
7476
) as never
7577
}
78+
// ------------------------------------------------------------------
79+
// EvaluateUnionFast
80+
//
81+
// Evaluates a union using a fast path. This evaluation assumes
82+
// all constituent types are already distinct and therefore skips
83+
// any broadening or deduplication steps. This assumption holds
84+
// for property keys in TProperties and tuple indices of TTuple.
85+
//
86+
// ------------------------------------------------------------------
87+
export type TEvaluateUnionFast<Types extends TSchema[],
88+
Result extends TSchema = (
89+
Types extends [infer Type extends TSchema] ? Type :
90+
Types extends [] ? TNever :
91+
TUnion<Types>
92+
)
93+
> = Result
94+
export function EvaluateUnionFast<Types extends TSchema[]>(types: [...Types]): TEvaluateUnionFast<Types> {
95+
const result = (
96+
Guard.IsEqual(types.length, 1) ? types[0] :
97+
Guard.IsEqual(types.length, 0) ? Never() :
98+
Union(types)
99+
)
100+
return result as never
101+
}

src/type/engine/evaluate/narrow.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ THE SOFTWARE.
3030

3131
import { Guard } from '../../../guard/index.ts'
3232
import { TSchema } from '../../types/schema.ts'
33-
import { TNever, Never } from "../../types/never.ts"
34-
import { TCompare, TCompareResult, Compare, ResultLeftInside, ResultRightInside, ResultEqual } from "./compare.ts"
33+
import { TNever, Never } from '../../types/never.ts'
34+
import { TCompare, TCompareResult, Compare, ResultLeftInside, ResultRightInside, ResultEqual } from './compare.ts'
3535

3636
// ------------------------------------------------------------------
3737
// Narrow

src/type/engine/indexed/from-tuple.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import { type TLiteral, Literal } from '../../types/literal.ts'
3333
import { type TNumber, IsNumber } from '../../types/number.ts'
3434
import { type TInteger, IsInteger } from '../../types/integer.ts'
3535

36-
import { type TEvaluateUnion, EvaluateUnion } from '../evaluate/evaluate.ts'
36+
import { type TEvaluateUnionFast, EvaluateUnionFast } from '../evaluate/evaluate.ts'
3737
import { type TExtends, Extends, ExtendsResult } from '../../extends/index.ts'
3838
import { type TFormatArrayIndexer, FormatArrayIndexer } from './array-indexer.ts'
3939

@@ -59,21 +59,21 @@ function IndexElementsWithIndexer<Types extends TSchema[], Indexer extends TSche
5959
type TFromTupleWithIndexer<Types extends TSchema[], Indexer extends TSchema,
6060
ArrayIndexer extends TSchema = TFormatArrayIndexer<Indexer>,
6161
Elements extends TSchema[] = TIndexElementsWithIndexer<Types, ArrayIndexer>,
62-
Result extends TSchema = TEvaluateUnion<Elements> // expensive
62+
Result extends TSchema = TEvaluateUnionFast<Elements>
6363
> = Result
6464
function FromTupleWithIndexer<Types extends TSchema[], Indexer extends TSchema>(types: [...Types], indexer: Indexer): TFromTupleWithIndexer<Types, Indexer> {
6565
const formattedArrayIndexer = FormatArrayIndexer(indexer)
6666
const elements = IndexElementsWithIndexer(types, formattedArrayIndexer) as TSchema[]
67-
return EvaluateUnion(elements) as never
67+
return EvaluateUnionFast(elements) as never
6868
}
6969
// ------------------------------------------------------------------
7070
// FromTupleNoIndexer
7171
// ------------------------------------------------------------------
7272
type TFromTupleWithoutIndexer<Types extends TSchema[],
73-
Result extends TSchema = TEvaluateUnion<Types> // expensive
73+
Result extends TSchema = TEvaluateUnionFast<Types>
7474
> = Result
7575
function FromTupleWithoutIndexer<Types extends TSchema[]>(types: [...Types]): TFromTupleWithoutIndexer<Types> {
76-
return EvaluateUnion(types) as never
76+
return EvaluateUnionFast(types) as never
7777
}
7878
// ------------------------------------------------------------------
7979
// FromTuple

src/type/engine/keyof/from-object.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ import { type TProperties } from '../../types/properties.ts'
3737
import { type TLiteral, type TLiteralValue, Literal, IsLiteralValue } from '../../types/literal.ts'
3838
import { ConvertToIntegerKey } from '../helpers/keys.ts'
3939

40-
import { type TEvaluateUnion, EvaluateUnion } from '../evaluate/evaluate.ts'
40+
import { type TEvaluateUnionFast, EvaluateUnionFast } from '../evaluate/evaluate.ts'
4141

4242
// ------------------------------------------------------------------
4343
// Keys
@@ -81,12 +81,12 @@ function FromPropertyKeys<Keys extends PropertyKey[]>(keys: [...Keys]): TFromPro
8181
export type TFromObject<Properties extends TProperties,
8282
PropertyKeys extends PropertyKey[] = TUnionToTuple<keyof Properties>,
8383
Variants extends TSchema [] = TFromPropertyKeys<PropertyKeys>,
84-
Result extends TSchema = TEvaluateUnion<Variants>
84+
Result extends TSchema = TEvaluateUnionFast<Variants>
8585
> = Result
8686

8787
export function FromObject<Properties extends TProperties>(properties: Properties): TFromObject<Properties> {
8888
const propertyKeys = Guard.Keys(properties)
8989
const variants = FromPropertyKeys(propertyKeys) as TSchema[]
90-
const result = EvaluateUnion(variants)
90+
const result = EvaluateUnionFast(variants)
9191
return result as never
9292
}

src/type/engine/keyof/from-tuple.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,13 @@ THE SOFTWARE.
3030

3131
import { type TSchema } from '../../types/index.ts'
3232
import { type TLiteral, Literal } from '../../types/literal.ts'
33-
import { type TEvaluateUnion, EvaluateUnion } from '../evaluate/evaluate.ts'
33+
import { type TEvaluateUnionFast, EvaluateUnionFast } from '../evaluate/evaluate.ts'
3434
export type TFromTuple<Types extends TSchema[], Result extends TSchema[] = []> = (
3535
Types extends [...infer Left extends TSchema[], infer _ extends TSchema]
3636
? TFromTuple<Left, [TLiteral<Left['length']>, ...Result]>
37-
: TEvaluateUnion<Result>
37+
: TEvaluateUnionFast<Result>
3838
)
3939
export function FromTuple<Types extends TSchema[]>(types: [...Types]): TFromTuple<Types> {
4040
const result = types.map((_, index) => Literal(index))
41-
return EvaluateUnion(result) as never
41+
return EvaluateUnionFast(result) as never
4242
}

0 commit comments

Comments
 (0)