Skip to content

Commit 2035a1c

Browse files
committed
Dependent If Type
1 parent 1d1006e commit 2035a1c

5 files changed

Lines changed: 91 additions & 59 deletions

File tree

example/index.ts

Lines changed: 11 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -6,65 +6,17 @@ import Schema from 'typebox/schema'
66
import Value from 'typebox/value'
77
import Type from 'typebox'
88

9-
// ------------------------------------------------------------------
10-
// Settings
11-
// ------------------------------------------------------------------
9+
const A = Type.If(Type.Script('never'), Type.Literal('hello'), Type.Literal(1))
1210

13-
System.Settings.Set({ enumerableKind: false })
11+
console.log(A)
1412

15-
// ------------------------------------------------------------------
16-
// Guard
17-
// ------------------------------------------------------------------
13+
type A = Type.Static<typeof A>
14+
type B = Schema.XStatic<typeof A>
1815

19-
const A = Guard.GraphemeCount('type-📦') // 6
20-
const B = Guard.HasPropertyKey({ x: 1 }, 'x') // true
21-
22-
// ------------------------------------------------------------------
23-
// Type
24-
// ------------------------------------------------------------------
25-
26-
const T = Type.Object({
27-
x: Type.Number(),
28-
y: Type.Number(),
29-
z: Type.Number()
30-
})
31-
32-
// ------------------------------------------------------------------
33-
// Script
34-
// ------------------------------------------------------------------
35-
36-
const S = Type.Script({ T }, `{
37-
[K in keyof T]: T[K] | null
38-
}`)
39-
40-
// ------------------------------------------------------------------
41-
// Infer
42-
// ------------------------------------------------------------------
43-
44-
type T = Type.Static<typeof T>
45-
type S = Type.Static<typeof S>
46-
47-
// ------------------------------------------------------------------
48-
// Parse
49-
// ------------------------------------------------------------------
50-
51-
const R = Value.Parse(T, { x: 1, y: 2, z: 3 })
52-
53-
// ------------------------------------------------------------------
54-
// Compile
55-
// ------------------------------------------------------------------
56-
const C = Compile(S)
57-
58-
const X = C.Parse({ x: 1, y: 2, z: 3 })
59-
60-
// ------------------------------------------------------------------
61-
// Format
62-
// ------------------------------------------------------------------
63-
64-
const E = Format.IsEmail('user@domain.com')
65-
66-
// ------------------------------------------------------------------
67-
// Schema
68-
// ------------------------------------------------------------------
69-
70-
const D = Schema.Parse({ const: 'hello' }, 'hello')
16+
const X = Type.Script(`{
17+
x: number with { description: 'hello' }
18+
y: number
19+
z: number
20+
} & if { x: 1 } then { y: 2 } else
21+
if { x: 2 } then { y: 3 }
22+
`)

src/type/types/if.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
/*--------------------------------------------------------------------------
2+
3+
TypeBox
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2017-2026 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+
// deno-fmt-ignore-file
30+
31+
import { Memory } from '../../system/memory/index.ts'
32+
import { type StaticType, type StaticDirection } from './static.ts'
33+
import { type TSchema, type TSchemaOptions, IsKind } from './schema.ts'
34+
import { type TProperties } from './properties.ts'
35+
36+
// ------------------------------------------------------------------
37+
// Static
38+
// ------------------------------------------------------------------
39+
export type StaticIf<Stack extends string[], Direction extends StaticDirection, Context extends TProperties, This extends TProperties, If extends TSchema, Then extends TSchema, Else extends TSchema,
40+
StaticIf extends unknown = StaticType<Stack, Direction, Context, This, If>,
41+
StaticThen extends unknown = StaticType<Stack, Direction, Context, This, Then>,
42+
StaticElse extends unknown = StaticType<Stack, Direction, Context, This, Else>,
43+
Result extends unknown = (StaticIf & StaticThen) | Exclude<StaticElse, StaticIf>
44+
> = Result
45+
// ------------------------------------------------------------------
46+
// Type
47+
// ------------------------------------------------------------------
48+
/** Represents a Conditionally Dependent If Type */
49+
export interface TIf<If extends TSchema = TSchema, Then extends TSchema = TSchema, Else extends TSchema = TSchema> extends TSchema {
50+
'~kind': 'If'
51+
if: If
52+
then: Then
53+
else: Else
54+
}
55+
// ------------------------------------------------------------------
56+
// Factory
57+
// ------------------------------------------------------------------
58+
/** Creates a Conditionally Dependent If Type */
59+
export function If<If extends TSchema, Then extends TSchema, Else extends TSchema>(if_: If, then_: Then, else_: Else, options: TSchemaOptions = {}): TIf<If, Then, Else> {
60+
return Memory.Create({ '~kind': 'If' }, { if: if_, then: then_, else: else_ }, options) as never
61+
}
62+
// ------------------------------------------------------------------
63+
// Guard
64+
// ------------------------------------------------------------------
65+
/** Returns true if the given value is TIf. */
66+
export function IsIf(value: unknown): value is TIf {
67+
return IsKind(value, 'If')
68+
}
69+
70+
// ------------------------------------------------------------------
71+
// Options
72+
// ------------------------------------------------------------------
73+
/** Extracts options from a TIf. */
74+
export function IfOptions(type: TIf): TSchemaOptions {
75+
return Memory.Discard(type, ['~kind', 'if', 'then', 'else'])
76+
}

src/type/types/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export * from './enum.ts'
5252
export * from './function.ts'
5353
export * from './generic.ts'
5454
export * from './identifier.ts'
55+
export * from './if.ts'
5556
export * from './infer.ts'
5657
export * from './integer.ts'
5758
export * from './intersect.ts'

src/type/types/static.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ import type { StaticCyclic, TCyclic } from './cyclic.ts'
4141
import type { StaticEnum, TEnum, TEnumValue } from './enum.ts'
4242
import type { StaticFunction, TFunction } from './function.ts'
4343
import type { StaticInteger, TInteger } from './integer.ts'
44+
import type { StaticIf, TIf } from './if.ts'
4445
import type { StaticIntersect, TIntersect } from './intersect.ts'
4546
import type { StaticIterator, TIterator } from './iterator.ts'
4647
import type { StaticLiteral, TLiteral, TLiteralValue } from './literal.ts'
@@ -89,6 +90,7 @@ export type StaticType<Stack extends string[], Direction extends StaticDirection
8990
Type extends TConstructor<infer Parameters extends TSchema[], infer ReturnType extends TSchema> ? StaticConstructor<Stack, Direction, Context, This, Parameters, ReturnType> :
9091
Type extends TEnum<infer Values extends TEnumValue[]> ? StaticEnum<Values> :
9192
Type extends TFunction<infer Parameters extends TSchema[], infer ReturnType extends TSchema> ? StaticFunction<Stack, Direction, Context, This, Parameters, ReturnType> :
93+
Type extends TIf<infer If extends TSchema, infer Then extends TSchema, infer Else extends TSchema> ? StaticIf<Stack, Direction, Context, This, If, Then, Else> :
9294
Type extends TInteger ? StaticInteger :
9395
Type extends TIntersect<infer Types extends TSchema[]> ? StaticIntersect<Stack, Direction, Context, This, Types> :
9496
Type extends TIterator<infer Types extends TSchema> ? StaticIterator<Stack, Direction, Context, This, Types> :

src/typebox.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ export { Enum, IsEnum, type TEnum, type TEnumValue } from './type/types/enum.ts'
9595
export { Function, IsFunction, type TFunction } from './type/types/function.ts'
9696
export { Generic, IsGeneric, type TGeneric } from './type/types/generic.ts'
9797
export { Identifier, IsIdentifier, type TIdentifier } from './type/types/identifier.ts'
98+
export { If, IsIf, type TIf } from './type/types/if.ts'
9899
export { Infer, IsInfer, type TInfer } from './type/types/infer.ts'
99100
export { Integer, IsInteger, type TInteger } from './type/types/integer.ts'
100101
export { Intersect, IsIntersect, type TIntersect } from './type/types/intersect.ts'

0 commit comments

Comments
 (0)