Skip to content

Commit 56b760c

Browse files
authored
Revision 0.34.1 (#1080)
* Implement Computed Deref Types for Import * ChangeLog
1 parent 53c3d75 commit 56b760c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+2075
-1072
lines changed

changelog/0.34.0.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
### 0.34.0
2+
- [Revision 0.34.1](https://github.com/sinclairzx81/typebox/pull/1080)
3+
- Implement Computed Type Deref in Modules
4+
15
## [0.34.0](https://www.npmjs.com/package/@sinclair/typebox/v/0.34.0)
26

37
## Overview

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@sinclair/typebox",
3-
"version": "0.34.0",
3+
"version": "0.34.1",
44
"description": "Json Schema Type Builder with Static Type Resolution for TypeScript",
55
"keywords": [
66
"typescript",

readme.md

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,22 +1074,32 @@ const T = Type.Object({ // const T: TObject<{
10741074
10751075
### Module
10761076
1077-
Syntax Types support Module parsing, which is useful for processing multiple TypeScript types. Module parsing supports type alias and interface definitions. Generics are currently unsupported as of 0.34.0.
1077+
Syntax Types also support Module parsing. This can provide a more terse syntax for creating Module definitions, but comes with an inference performance cost. Module parsing supports interface and type alias definitions. Generics types are currently unsupported.
10781078
10791079
```typescript
1080-
const Foo = Parse(`module Foo {
1081-
1082-
export type A = string
1083-
1084-
export type B = number
1085-
1086-
export type C = A | B
1080+
const Module = Parse(`module {
1081+
1082+
export interface User {
1083+
id: string
1084+
name: string
1085+
email: string
1086+
}
1087+
1088+
export type PartialUser = (
1089+
Pick<User, 'id'> &
1090+
Partial<Omit<User, 'id'>>
1091+
)
10871092
10881093
}`)
10891094

1090-
const C = Foo.Import('C') // const C: TImport<{
1091-
// ...
1092-
// }, 'C'>
1095+
const PartialUser = Module.Import('PartialUser') // TImport<{...}, 'PartialUser'>
1096+
1097+
type PartialUser = Static<typeof PartialUser> // type PartialUser = {
1098+
// id: string,
1099+
// } & {
1100+
// name?: string,
1101+
// email?: string,
1102+
// }
10931103
```
10941104
10951105
<a name='syntax-context'></a>
@@ -1883,12 +1893,12 @@ The following table lists esbuild compiled and minified sizes for each TypeBox m
18831893
┌──────────────────────┬────────────┬────────────┬─────────────┐
18841894
│ (index) │ CompiledMinifiedCompression
18851895
├──────────────────────┼────────────┼────────────┼─────────────┤
1886-
typebox/compiler'121.7 kb'' 53.4 kb''2.28 x'
1887-
typebox/errors' 75.3 kb'' 33.4 kb''2.25 x'
1888-
typebox/syntax'120.1 kb'' 50.5 kb''2.38 x'
1896+
typebox/compiler'122.4 kb'' 53.4 kb''2.29 x'
1897+
typebox/errors' 67.6 kb'' 29.6 kb''2.28 x'
1898+
typebox/syntax'132.9 kb'' 54.2 kb''2.45 x'
18891899
typebox/system' 7.4 kb'' 3.2 kb''2.33 x'
1890-
typebox/value'160.3 kb'' 67.4 kb''2.38 x'
1891-
typebox' 96.2 kb'' 40.2 kb''2.39 x'
1900+
typebox/value'150.1 kb'' 62.2 kb''2.41 x'
1901+
typebox'106.8 kb'' 43.2 kb''2.47 x'
18921902
└──────────────────────┴────────────┴────────────┴─────────────┘
18931903
```
18941904

src/syntax/runtime.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -324,11 +324,12 @@ const FactorIndexArray = (Type: Types.TSchema, IndexArray: unknown[]): Types.TSc
324324
const [Left, Right] = DestructureRight(IndexArray) as [unknown[], Types.TSchema[]]
325325
return (
326326
!Types.ValueGuard.IsUndefined(Right) ? (
327-
Right.length === 1 ? Types.Index(FactorIndexArray(Type, Left), Right[0]) :
327+
// note: Indexed types require reimplementation to replace `[number]` indexers
328+
Right.length === 1 ? Types.Index(FactorIndexArray(Type, Left), Right[0]) as never :
328329
Right.length === 0 ? Types.Array(FactorIndexArray(Type, Left)) :
329330
Types.Never()
330331
) : Type
331-
)
332+
)
332333
}
333334
// prettier-ignore
334335
const FactorMapping = (KeyOf: boolean, Type: Types.TSchema, IndexArray: unknown[], Extends: Types.TSchema[]) => {

src/syntax/static.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -776,7 +776,7 @@ type Partial = Static.Tuple<[
776776
// prettier-ignore
777777
interface RequiredMapping extends Static.IMapping {
778778
output: this['input'] extends ['Required', LAngle, infer Type extends Types.TSchema, RAngle]
779-
? Types.TPartial<Type>
779+
? Types.TRequired<Type>
780780
: never
781781
}
782782
// prettier-ignore
@@ -788,8 +788,8 @@ type Required = Static.Tuple<[
788788
// ------------------------------------------------------------------
789789
// prettier-ignore
790790
interface PickMapping extends Static.IMapping {
791-
output: this['input'] extends ['Pick', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
792-
? Types.TPick<Type, Types.TIndexPropertyKeys<PropertyKey>>
791+
output: this['input'] extends ['Pick', LAngle, infer Type extends Types.TSchema, Comma, infer Key extends Types.TSchema, RAngle]
792+
? Types.TPick<Type, Key>
793793
: never
794794
}
795795
// prettier-ignore
@@ -801,8 +801,8 @@ type Pick = Static.Tuple<[
801801
// ------------------------------------------------------------------
802802
// prettier-ignore
803803
interface OmitMapping extends Static.IMapping {
804-
output: this['input'] extends ['Omit', LAngle, infer Type extends Types.TSchema, Comma, infer PropertyKey extends Types.TSchema, RAngle]
805-
? Types.TOmit<Type, Types.TIndexPropertyKeys<PropertyKey>>
804+
output: this['input'] extends ['Omit', LAngle, infer Type extends Types.TSchema, Comma, infer Key extends Types.TSchema, RAngle]
805+
? Types.TOmit<Type, Key>
806806
: never
807807
}
808808
// prettier-ignore

src/type/array/array.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,6 @@ export interface TArray<T extends TSchema = TSchema> extends TSchema, ArrayOptio
5454
items: T
5555
}
5656
/** `[Json]` Creates an Array type */
57-
export function Array<T extends TSchema>(items: T, options?: ArrayOptions): TArray<T> {
57+
export function Array<Type extends TSchema>(items: Type, options?: ArrayOptions): TArray<Type> {
5858
return CreateType({ [Kind]: 'Array', type: 'array', items }, options) as never
5959
}

src/type/awaited/awaited.ts

Lines changed: 57 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -26,76 +26,96 @@ THE SOFTWARE.
2626
2727
---------------------------------------------------------------------------*/
2828

29+
import { CreateType } from '../create/type'
30+
import { Ensure } from '../helpers/index'
2931
import type { TSchema, SchemaOptions } from '../schema/index'
32+
import { Computed, type TComputed } from '../computed/index'
3033
import { Intersect, type TIntersect } from '../intersect/index'
3134
import { Union, type TUnion } from '../union/index'
3235
import { type TPromise } from '../promise/index'
33-
import { CreateType } from '../create/type'
36+
import { Ref, type TRef } from '../ref/index'
3437

3538
// ------------------------------------------------------------------
3639
// TypeGuard
3740
// ------------------------------------------------------------------
38-
import { IsIntersect, IsUnion, IsPromise } from '../guard/kind'
39-
// ------------------------------------------------------------------
40-
// FromRest
41-
// ------------------------------------------------------------------
41+
import { IsIntersect, IsUnion, IsPromise, IsRef, IsComputed } from '../guard/kind'
42+
43+
// ----------------------------------------------------------------
44+
// FromComputed
45+
// ----------------------------------------------------------------
4246
// prettier-ignore
43-
type TFromRest<T extends TSchema[], Acc extends TSchema[] = []> =
44-
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
45-
? TFromRest<R, [...Acc, TAwaited<L>]>
46-
: Acc
47+
type TFromComputed<Target extends string, Parameters extends TSchema[]> = Ensure<(
48+
TComputed<'Awaited', [TComputed<Target, Parameters>]>
49+
)>
50+
// prettier-ignore
51+
function FromComputed<Target extends string, Parameters extends TSchema[]>(target: Target, parameters: Parameters): TFromComputed<Target, Parameters> {
52+
return Computed('Awaited', [Computed(target, parameters)]) as never
53+
}
54+
// ----------------------------------------------------------------
55+
// Ref
56+
// ----------------------------------------------------------------
57+
type TFromRef<Ref extends string> = Ensure<TComputed<'Awaited', [TRef<Ref>]>>
4758
// prettier-ignore
48-
function FromRest<T extends TSchema[]>(T: [...T]) : TFromRest<T> {
49-
return T.map(L => AwaitedResolve(L)) as never
59+
function FromRef<Ref extends string>($ref: Ref): TFromRef<Ref> {
60+
return Computed('Awaited', [Ref($ref)]) as never
5061
}
5162
// ----------------------------------------------------------------
5263
// FromIntersect
5364
// ----------------------------------------------------------------
5465
// prettier-ignore
55-
type TFromIntersect<T extends TSchema[]> = TIntersect<TFromRest<T>>
66+
type TFromIntersect<Types extends TSchema[]> = (
67+
TIntersect<TFromRest<Types>>
68+
)
5669
// prettier-ignore
57-
function FromIntersect<T extends TSchema[]>(T: [...T]): TFromIntersect<T> {
58-
return Intersect(FromRest(T) as TSchema[]) as never
70+
function FromIntersect<Types extends TSchema[]>(types: [...Types]): TFromIntersect<Types> {
71+
return Intersect(FromRest(types) as TSchema[]) as never
5972
}
6073
// ----------------------------------------------------------------
6174
// FromUnion
6275
// ----------------------------------------------------------------
6376
// prettier-ignore
64-
type TFromUnion<T extends TSchema[]> = TUnion<TFromRest<T>>
77+
type TFromUnion<Types extends TSchema[]> = TUnion<TFromRest<Types>>
6578
// prettier-ignore
66-
function FromUnion<T extends TSchema[]>(T: [...T]): TFromUnion<T> {
67-
return Union(FromRest(T) as TSchema[]) as never
79+
function FromUnion<Types extends TSchema[]>(types: [...Types]): TFromUnion<Types> {
80+
return Union(FromRest(types) as TSchema[]) as never
6881
}
6982
// ----------------------------------------------------------------
7083
// Promise
7184
// ----------------------------------------------------------------
72-
type TFromPromise<T extends TSchema> = TAwaited<T>
85+
type TFromPromise<Type extends TSchema> = TAwaited<Type>
7386
// prettier-ignore
74-
function FromPromise<T extends TSchema>(T: T): TFromPromise<T> {
75-
return AwaitedResolve(T) as never
87+
function FromPromise<Type extends TSchema>(type: Type): TFromPromise<Type> {
88+
return Awaited(type) as never
7689
}
77-
// ----------------------------------------------------------------
78-
// AwaitedResolve
79-
// ----------------------------------------------------------------
90+
// ------------------------------------------------------------------
91+
// FromRest
92+
// ------------------------------------------------------------------
8093
// prettier-ignore
81-
function AwaitedResolve<T extends TSchema>(T: T): TAwaited<T> {
82-
return (
83-
IsIntersect(T) ? FromIntersect(T.allOf) :
84-
IsUnion(T) ? FromUnion(T.anyOf) :
85-
IsPromise(T) ? FromPromise(T.item) :
86-
T
87-
) as never
94+
type TFromRest<Types extends TSchema[], Result extends TSchema[] = []> = (
95+
Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]]
96+
? TFromRest<Right, [...Result, TAwaited<Left>]>
97+
: Result
98+
)
99+
// prettier-ignore
100+
function FromRest<Types extends TSchema[]>(types: [...Types]) : TFromRest<Types> {
101+
return types.map(type => Awaited(type)) as never
88102
}
89103
// ------------------------------------------------------------------
90104
// TAwaited
91105
// ------------------------------------------------------------------
92106
// prettier-ignore
93-
export type TAwaited<T extends TSchema> =
94-
T extends TIntersect<infer S> ? TIntersect<TFromRest<S>> :
95-
T extends TUnion<infer S> ? TUnion<TFromRest<S>> :
96-
T extends TPromise<infer S> ? TAwaited<S> :
97-
T
107+
export type TAwaited<Type extends TSchema> = (
108+
Type extends TComputed<infer Target extends string, infer Parameters extends TSchema[]> ? TFromComputed<Target, Parameters> :
109+
Type extends TRef<infer Ref extends string> ? TFromRef<Ref> :
110+
Type extends TIntersect<infer Types extends TSchema[]> ? TIntersect<TFromRest<Types>> :
111+
Type extends TUnion<infer Types extends TSchema[]> ? TUnion<TFromRest<Types>> :
112+
Type extends TPromise<infer Type extends TSchema> ? TAwaited<Type> :
113+
Type
114+
)
98115
/** `[JavaScript]` Constructs a type by recursively unwrapping Promise types */
99-
export function Awaited<T extends TSchema>(T: T, options?: SchemaOptions): TAwaited<T> {
100-
return CreateType(AwaitedResolve(T), options) as never
116+
export function Awaited<T extends TSchema>(type: T, options?: SchemaOptions): TAwaited<T> {
117+
return CreateType(
118+
IsComputed(type) ? FromComputed(type.target, type.parameters) : IsIntersect(type) ? FromIntersect(type.allOf) : IsUnion(type) ? FromUnion(type.anyOf) : IsPromise(type) ? FromPromise(type.item) : IsRef(type) ? FromRef(type.$ref) : type,
119+
options,
120+
) as never
101121
}

src/type/computed/computed.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*--------------------------------------------------------------------------
2+
3+
@sinclair/typebox/type
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <[email protected]>
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 { TSchema, SchemaOptions } from '../schema/index'
30+
import { CreateType } from '../create/index'
31+
import { Kind } from '../symbols/symbols'
32+
33+
// ------------------------------------------------------------------
34+
// Computed
35+
// ------------------------------------------------------------------
36+
export interface TComputed<Target extends string = string, Parameters extends TSchema[] = []> extends TSchema {
37+
[Kind]: 'Computed'
38+
target: Target
39+
parameters: Parameters
40+
}
41+
/** `[Internal]` Creates a deferred computed type. This type is used exclusively in modules to defer resolution of computable types that contain interior references */
42+
export function Computed<Target extends string, Parameters extends TSchema[]>(target: Target, parameters: [...Parameters], options?: SchemaOptions): TComputed<Target, Parameters> {
43+
return CreateType({ [Kind]: 'Computed', target, parameters }, options) as never
44+
}

src/type/computed/index.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*--------------------------------------------------------------------------
2+
3+
@sinclair/typebox/type
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2017-2024 Haydn Paterson (sinclair) <[email protected]>
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+
export * from './computed'

0 commit comments

Comments
 (0)