Skip to content

Commit 59e912a

Browse files
committed
Evaluate and Extends Logic
1 parent 4305098 commit 59e912a

12 files changed

Lines changed: 133 additions & 97 deletions

File tree

design/syntax/syntax.ts

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ const Base = Runtime.Union([
283283
Runtime.Ref('Constructor'),
284284
Runtime.Ref('_Function_'),
285285
Runtime.Ref('Mapped'),
286-
Runtime.Ref('_If_'),
286+
Runtime.Ref('IfThenElse'),
287287
Runtime.Ref('Options'),
288288
Runtime.Ref('GenericCall'),
289289
Runtime.Ref('Reference')
@@ -639,12 +639,11 @@ const Mapped = Runtime.Tuple([
639639
Runtime.Const(RBrace),
640640
])
641641
// ------------------------------------------------------------------
642-
// If
642+
// IfThenElse
643643
// ------------------------------------------------------------------
644-
const _If_ = Runtime.Union([
644+
const IfThenElse = Runtime.Union([
645645
Runtime.Tuple([Runtime.Const('if'), Runtime.Ref('Type'), Runtime.Const('then'), Runtime.Ref('Type'), Runtime.Const('else'), Runtime.Ref('Type')]),
646-
Runtime.Tuple([Runtime.Const('if'), Runtime.Ref('Type'), Runtime.Const('then'), Runtime.Ref('Type')]),
647-
Runtime.Tuple([Runtime.Const('if'), Runtime.Ref('Type'), Runtime.Const('else'), Runtime.Ref('Type')])
646+
Runtime.Tuple([Runtime.Const('if'), Runtime.Ref('Type'), Runtime.Const('then'), Runtime.Ref('Type')])
648647
])
649648
// ------------------------------------------------------------------
650649
// Options
@@ -1018,9 +1017,8 @@ export const SyntaxModule = new Runtime.Module({
10181017
MappedAs,
10191018
Mapped,
10201019

1021-
_If_,
1022-
10231020
Reference,
1021+
IfThenElse,
10241022
Options,
10251023

10261024
// ----------------------------------------------------------------

example/index.ts

Lines changed: 24 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,38 @@
1-
import Compile from 'typebox/compile'
2-
import System from 'typebox/system'
3-
import Guard from 'typebox/guard'
4-
import Format from 'typebox/format'
5-
import Schema from 'typebox/schema'
6-
import Value from 'typebox/value'
71
import Type from 'typebox'
82

9-
// ------------------------------------------------------------------
10-
// Settings
11-
// ------------------------------------------------------------------
3+
// investigating Extends logic
124

13-
System.Settings.Set({ enumerableKind: false })
5+
const { A, B, C, Vector } = Type.Script(`
6+
7+
type A = if number then 1 // 1 | unknown - (technically 1 & (unknown & not number))
8+
type B = if number then 1 else 'hello' // 1 | 'hello'
9+
type C = if number then 1 else never // 1
1410
15-
// ------------------------------------------------------------------
16-
// Guard
17-
// ------------------------------------------------------------------
11+
// which approximates as the following
1812
19-
const A = Guard.GraphemeCount('type-📦') // 6
20-
const B = Guard.HasPropertyKey({ x: 1 }, 'x') // true
13+
type IfThenElse<If, Then, Else> = (If & Then) | Exclude<Else, If>
2114
22-
// ------------------------------------------------------------------
23-
// Type
24-
// ------------------------------------------------------------------
15+
// and would be used in contexts like the following
2516
26-
const T = Type.Object({
27-
x: Type.Number(),
28-
y: Type.Number(),
29-
z: Type.Number()
30-
})
17+
// Rules
18+
type RuleA = if { x: 1 } then { y: 1 }
19+
type RuleB = if { x: 2 } then { y: 2 }
20+
type RuleC = if { x: 3 } then { y: 3 }
3121
32-
// ------------------------------------------------------------------
33-
// Script
34-
// ------------------------------------------------------------------
3522
36-
const S = Type.Script({ T }, `{
37-
[K in keyof T]: T[K] | null
38-
}`)
23+
// Vector Intersected with Rules
24+
type Vector = {
25+
x: number
26+
y: number
27+
} & if { x: 1 } then { y: 1 } else
28+
if { x: 2 } then { y: 2 }
29+
`)
3930

40-
// ------------------------------------------------------------------
41-
// Infer
42-
// ------------------------------------------------------------------
31+
type A = Type.Static<typeof A>
32+
type B = Type.Static<typeof B>
33+
type C = Type.Static<typeof C>
4334

44-
type T = Type.Static<typeof T>
45-
type S = Type.Static<typeof S>
35+
type Vector = Type.Static<typeof Vector>
4636

47-
// ------------------------------------------------------------------
48-
// Parse
49-
// ------------------------------------------------------------------
5037

51-
const R = Value.Parse(T, { x: 1, y: 2, z: 3 })
5238

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')

src/type/engine/evaluate/evaluate.ts

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

3131
import { Guard } from '../../../guard/index.ts'
3232
import { type TSchema } from '../../types/schema.ts'
33+
import { type TIfThenElse, IsIfThenElse } from '../../types/if_then_else.ts'
3334
import { type TIntersect, IsIntersect } from '../../types/intersect.ts'
34-
import { type TDistribute, Distribute } from './distribute.ts'
35-
import { type TBroaden, Broaden } from './broaden.ts'
3635
import { type TUnion, Union, IsUnion } from '../../types/union.ts'
3736
import { type TNever, Never } from '../../types/never.ts'
3837

38+
import { type TDistribute, Distribute } from './distribute.ts'
39+
import { type TBroaden, Broaden } from './broaden.ts'
40+
import { type TExcludeAction, ExcludeAction } from '../exclude/index.ts'
41+
42+
// ------------------------------------------------------------------
43+
// EvaluateIfThenElse
44+
// ------------------------------------------------------------------
45+
export type TEvaluateIfThenElse<If extends TSchema, Then extends TSchema, Else extends TSchema,
46+
Left extends TSchema = TEvaluateIntersect<[If, Then]>,
47+
Right extends TSchema = TEvaluateType<TExcludeAction<Else, Left>>,
48+
Result extends TSchema = TEvaluateUnion<[Left, Right]>
49+
> = Result
50+
export function EvaluateIfThenElse<If extends TSchema, Then extends TSchema, Else extends TSchema>
51+
(if_: If, then_: Then, else_: Else): TEvaluateIfThenElse<If, Then, Else> {
52+
const left = EvaluateIntersect([if_, then_])
53+
const right = EvaluateType(ExcludeAction(else_, left, {}))
54+
const result = EvaluateUnion([left, right])
55+
return result as never
56+
}
3957
// ------------------------------------------------------------------
4058
// EvaluateIntersect
4159
// ------------------------------------------------------------------
@@ -63,13 +81,15 @@ export function EvaluateUnion<Types extends TSchema[]>(types: [...Types]): TEval
6381
// ------------------------------------------------------------------
6482
export type TEvaluateType<Type extends TSchema,
6583
Result extends TSchema = (
84+
Type extends TIfThenElse<infer If extends TSchema, infer Then extends TSchema, infer Else extends TSchema> ? TEvaluateIfThenElse<If, Then, Else> :
6685
Type extends TIntersect<infer Types extends TSchema[]> ? TEvaluateIntersect<Types> :
6786
Type extends TUnion<infer Types extends TSchema[]> ? TEvaluateUnion<Types> :
6887
Type
6988
)
7089
> = Result
7190
export function EvaluateType<Type extends TSchema>(type: Type): TEvaluateType<Type> {
7291
return (
92+
IsIfThenElse(type) ? EvaluateIfThenElse(type.if, type.then, type.else) :
7393
IsIntersect(type) ? EvaluateIntersect(type.allOf) :
7494
IsUnion(type) ? EvaluateUnion(type.anyOf) :
7595
type

src/type/engine/instantiate.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ import { type TDeferred, Deferred, IsDeferred } from '../types/deferred.ts'
5050
import { type TFunction, _Function_, IsFunction, FunctionOptions } from '../types/function.ts'
5151
import { type TCall, IsCall } from '../types/call.ts'
5252
import { type TIdentifier } from '../types/identifier.ts'
53-
import { type TIf, If, IsIf, IfOptions } from '../types/if.ts'
53+
import { type TIfThenElse, IfThenElse, IsIfThenElse, IfThenElseOptions } from '../types/if_then_else.ts'
5454
import { type TIntersect, Intersect, IsIntersect, IntersectOptions } from '../types/intersect.ts'
5555
import { type TIterator, Iterator, IsIterator, IteratorOptions } from '../types/iterator.ts'
5656
import { type TObject, Object, IsObject, ObjectOptions } from '../types/object.ts'
@@ -309,7 +309,7 @@ export type TInstantiateType<Context extends TProperties, State extends TState,
309309
Type extends TConstructor<infer Parameters extends TSchema[], infer InstanceType extends TSchema> ? TConstructor<TInstantiateTypes<Context, State,Parameters>, TInstantiateType<Context, State, InstanceType>> :
310310
Type extends TDeferred<infer Action extends string, infer Types extends TSchema[]> ? TInstantiateDeferred<Context, State, Action, Types> :
311311
Type extends TFunction<infer Parameters extends TSchema[], infer ReturnType extends TSchema> ? TFunction<TInstantiateTypes<Context, State, Parameters>, TInstantiateType<Context, State,ReturnType>> :
312-
Type extends TIf<infer If extends TSchema, infer Then extends TSchema, infer Else extends TSchema> ? TIf<TInstantiateType<Context, State, If>, TInstantiateType<Context, State, Then>, TInstantiateType<Context, State, Else>> :
312+
Type extends TIfThenElse<infer If extends TSchema, infer Then extends TSchema, infer Else extends TSchema> ? TIfThenElse<TInstantiateType<Context, State, If>, TInstantiateType<Context, State, Then>, TInstantiateType<Context, State, Else>> :
313313
Type extends TIntersect<infer Types extends TSchema[]> ? TIntersect<TInstantiateTypes<Context, State, Types>> :
314314
Type extends TIterator<infer Type extends TSchema> ? TIterator<TInstantiateType<Context, State, Type>> :
315315
Type extends TObject<infer Properties extends TProperties> ? TObject<TInstantiateProperties<Context, State, Properties>> :
@@ -340,7 +340,7 @@ export function InstantiateType<Context extends TProperties, State extends TStat
340340
IsConstructor(type) ? Constructor(InstantiateTypes(context, state, type.parameters), InstantiateType(context, state, type.instanceType) as never, ConstructorOptions(type)) :
341341
IsDeferred(type) ? InstantiateDeferred(context, state, type.action, type.parameters, type.options) :
342342
IsFunction(type) ? _Function_(InstantiateTypes(context, state, type.parameters), InstantiateType(context, state, type.returnType) as never, FunctionOptions(type)) :
343-
IsIf(type) ? If(InstantiateType(context, state, type.if), InstantiateType(context, state, type.then), InstantiateType(context, state, type.else), IfOptions(type)) :
343+
IsIfThenElse(type) ? IfThenElse(InstantiateType(context, state, type.if), InstantiateType(context, state, type.then), InstantiateType(context, state, type.else), IfThenElseOptions(type)) :
344344
IsIntersect(type) ? Intersect(InstantiateTypes(context, state, type.allOf), IntersectOptions(type)) :
345345
IsIterator(type) ? Iterator(InstantiateType(context, state, type.iteratorItems), IteratorOptions(type)) :
346346
IsObject(type) ? Object(InstantiateProperties(context, state, type.properties), ObjectOptions(type)) :

src/type/extends/extends_left.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ import { type TExtendsBoolean, ExtendsBoolean } from './boolean.ts'
3636
import { type TExtendsConstructor, ExtendsConstructor } from './constructor.ts'
3737
import { type TExtendsEnum, ExtendsEnum } from './enum.ts'
3838
import { type TExtendsFunction, ExtendsFunction } from './function.ts'
39+
import { type TExtendsIfThenElse, ExtendsIfThenElse } from './if_then_else.ts'
3940
import { type TExtendsInteger, ExtendsInteger } from './integer.ts'
4041
import { type TExtendsIntersect, ExtendsIntersect } from './intersect.ts'
4142
import { type TExtendsIterator, ExtendsIterator } from './iterator.ts'
@@ -65,6 +66,7 @@ import { type TBoolean, IsBoolean } from '../types/boolean.ts'
6566
import { type TConstructor, IsConstructor } from '../types/constructor.ts'
6667
import { type TEnum, type TEnumValue, IsEnum } from '../types/enum.ts'
6768
import { type TFunction, IsFunction } from '../types/function.ts'
69+
import { type TIfThenElse, IsIfThenElse } from '../types/if_then_else.ts'
6870
import { type TInteger, IsInteger } from '../types/integer.ts'
6971
import { type TIntersect, IsIntersect } from '../types/intersect.ts'
7072
import { type TIterator, IsIterator } from '../types/iterator.ts'
@@ -99,6 +101,7 @@ export type TExtendsLeft<Inferred extends TProperties, Left extends TSchema, Rig
99101
Left extends TConstructor<infer Parameters extends TSchema[], infer InstanceType extends TSchema> ? TExtendsConstructor<Inferred, Parameters, InstanceType, Right> :
100102
Left extends TEnum<infer Values extends TEnumValue[]> ? TExtendsEnum<Inferred, TEnum<Values>, Right> :
101103
Left extends TFunction<infer Parameters extends TSchema[], infer ReturnType extends TSchema> ? TExtendsFunction<Inferred, Parameters, ReturnType, Right> :
104+
Left extends TIfThenElse<infer If extends TSchema, infer Then extends TSchema, infer Else extends TSchema> ? TExtendsIfThenElse<Inferred, If, Then, Else, Right> :
102105
Left extends TInteger ? TExtendsInteger<Inferred, Left, Right> :
103106
Left extends TIntersect<infer Types extends TSchema[]> ? TExtendsIntersect<Inferred, Types, Right> :
104107
Left extends TIterator<infer Type extends TSchema> ? TExtendsIterator<Inferred, Type, Right> :
@@ -130,6 +133,7 @@ export function ExtendsLeft<Inferred extends TProperties, Left extends TSchema,
130133
IsConstructor(left) ? ExtendsConstructor(inferred, left.parameters, left.instanceType, right) :
131134
IsEnum(left) ? ExtendsEnum(inferred, left, right) :
132135
IsFunction(left) ? ExtendsFunction(inferred, left.parameters, left.returnType, right) :
136+
IsIfThenElse(left) ? ExtendsIfThenElse(inferred, left.if, left.then, left.else, right) :
133137
IsInteger(left) ? ExtendsInteger(inferred, left, right) :
134138
IsIntersect(left) ? ExtendsIntersect(inferred, left.allOf, right) :
135139
IsIterator(left) ? ExtendsIterator(inferred, left.iteratorItems, right) :

src/type/extends/if_then_else.ts

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
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 { type TProperties } from '../types/properties.ts'
32+
import { type TSchema } from '../types/schema.ts'
33+
import { type TUnknown, Unknown } from '../types/unknown.ts'
34+
import { type TExtendsLeft, ExtendsLeft } from './extends_left.ts'
35+
36+
// ----------------------------------------------------------------------------
37+
// EvaluateIfThenElse
38+
// ----------------------------------------------------------------------------
39+
import { type TEvaluateIfThenElse, EvaluateIfThenElse } from '../engine/evaluate/index.ts'
40+
41+
export type TExtendsIfThenElse<Inferred extends TProperties, If extends TSchema, Then extends TSchema, Else extends TSchema, Right extends TSchema,
42+
// Evaluated extends TSchema = TEvaluateIfThenElse<If, Then, Else>
43+
> = TExtendsLeft<Inferred, TUnknown, Right>
44+
export function ExtendsIfThenElse<Inferred extends TProperties, If extends TSchema, Then extends TSchema, Else extends TSchema, Right extends TSchema>
45+
(inferred: Inferred, if_: If, then_: Then, else_: Else, right: Right):
46+
TExtendsIfThenElse<Inferred, If, Then, Else, Right> {
47+
// const evaluated = EvaluateIfThenElse(if_, then_, else_)
48+
return ExtendsLeft(inferred, Unknown(), right) as never
49+
}

src/type/script/mapping.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1208,22 +1208,19 @@ export function MappedMapping(input: [unknown, unknown, unknown, unknown, unknow
12081208
)
12091209
}
12101210
// -------------------------------------------------------------------
1211-
// _If_: ['if', Type, 'then', Type, 'else', Type] | ['if', Type, 'then', Type] | ['if', Type, 'else', Type]
1211+
// IfThenElse: ['if', Type, 'then', Type, 'else', Type] | ['if', Type, 'then', Type]
12121212
// -------------------------------------------------------------------
1213-
export type T_If_Mapping<Input extends [unknown, unknown, unknown, unknown, unknown, unknown] | [unknown, unknown, unknown, unknown]> = (
1213+
export type TIfThenElseMapping<Input extends [unknown, unknown, unknown, unknown, unknown, unknown] | [unknown, unknown, unknown, unknown]> = (
12141214
Input extends ['if', infer If extends T.TSchema, 'then', infer Then extends T.TSchema, 'else', infer Else extends T.TSchema]
1215-
? T.TIf<If, Then, Else> :
1215+
? T.TIfThenElse<If, Then, Else> :
12161216
Input extends ['if', infer If extends T.TSchema, 'then', infer Then extends T.TSchema]
1217-
? T.TIf<If, Then, T.TUnknown> :
1218-
Input extends ['if', infer If extends T.TSchema, 'else', infer Else extends T.TSchema]
1219-
? T.TIf<If, T.TUnknown, Else> :
1217+
? T.TIfThenElse<If, Then, T.TUnknown> :
12201218
never
12211219
)
1222-
export function _If_Mapping(input: [unknown, unknown, unknown, unknown, unknown, unknown] | [unknown, unknown, unknown, unknown]): unknown {
1220+
export function IfThenElseMapping(input: [unknown, unknown, unknown, unknown, unknown, unknown] | [unknown, unknown, unknown, unknown]): unknown {
12231221
return (
1224-
Guard.IsEqual(input.length, 6) ? T.If(input[1] as T.TSchema, input[3] as T.TSchema, input[5] as T.TSchema) :
1225-
Guard.IsEqual(input[2], 'then') ? T.If(input[1] as T.TSchema, input[3] as T.TSchema, T.Unknown()) :
1226-
T.If(input[1] as T.TSchema, T.Unknown(), input[3] as T.TSchema)
1222+
Guard.IsEqual(input.length, 6) ? T.IfThenElse(input[1] as T.TSchema, input[3] as T.TSchema, input[5] as T.TSchema) :
1223+
T.IfThenElse(input[1] as T.TSchema, input[3] as T.TSchema, T.Unknown())
12271224
)
12281225
}
12291226
// -------------------------------------------------------------------

0 commit comments

Comments
 (0)