@nmtjs/type 0.4.7 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/dist/compiler.js +84 -38
  2. package/dist/compiler.js.map +1 -1
  3. package/dist/formats.js +1 -1
  4. package/dist/formats.js.map +1 -1
  5. package/dist/index.js +53 -22
  6. package/dist/index.js.map +1 -1
  7. package/dist/schemas/discriminated-union.js +9 -0
  8. package/dist/schemas/discriminated-union.js.map +1 -0
  9. package/dist/schemas/nullable.js +1 -6
  10. package/dist/schemas/nullable.js.map +1 -1
  11. package/dist/temporal.js +7 -7
  12. package/dist/temporal.js.map +1 -1
  13. package/dist/types/any.js +3 -43
  14. package/dist/types/any.js.map +1 -1
  15. package/dist/types/array.js +17 -63
  16. package/dist/types/array.js.map +1 -1
  17. package/dist/types/base.js +78 -41
  18. package/dist/types/base.js.map +1 -1
  19. package/dist/types/boolean.js +3 -43
  20. package/dist/types/boolean.js.map +1 -1
  21. package/dist/types/custom.js +8 -48
  22. package/dist/types/custom.js.map +1 -1
  23. package/dist/types/date.js +8 -0
  24. package/dist/types/date.js.map +1 -0
  25. package/dist/types/enum.js +10 -94
  26. package/dist/types/enum.js.map +1 -1
  27. package/dist/types/literal.js +3 -43
  28. package/dist/types/literal.js.map +1 -1
  29. package/dist/types/never.js +3 -26
  30. package/dist/types/never.js.map +1 -1
  31. package/dist/types/number.js +52 -186
  32. package/dist/types/number.js.map +1 -1
  33. package/dist/types/object.js +10 -131
  34. package/dist/types/object.js.map +1 -1
  35. package/dist/types/string.js +25 -65
  36. package/dist/types/string.js.map +1 -1
  37. package/dist/types/temporal.js +23 -328
  38. package/dist/types/temporal.js.map +1 -1
  39. package/dist/types/union.js +16 -90
  40. package/dist/types/union.js.map +1 -1
  41. package/dist/utils.js.map +1 -1
  42. package/package.json +3 -3
  43. package/src/compiler.ts +124 -41
  44. package/src/formats.ts +1 -1
  45. package/src/index.ts +145 -63
  46. package/src/schemas/discriminated-union.ts +49 -0
  47. package/src/schemas/nullable.ts +7 -13
  48. package/src/temporal.ts +8 -7
  49. package/src/types/any.ts +6 -46
  50. package/src/types/array.ts +38 -86
  51. package/src/types/base.ts +205 -81
  52. package/src/types/boolean.ts +13 -47
  53. package/src/types/custom.ts +21 -79
  54. package/src/types/date.ts +10 -0
  55. package/src/types/enum.ts +18 -107
  56. package/src/types/literal.ts +7 -63
  57. package/src/types/never.ts +6 -36
  58. package/src/types/number.ts +52 -188
  59. package/src/types/object.ts +61 -202
  60. package/src/types/string.ts +25 -61
  61. package/src/types/temporal.ts +53 -410
  62. package/src/types/union.ts +98 -138
  63. package/src/utils.ts +8 -0
  64. package/dist/constants.js +0 -2
  65. package/dist/constants.js.map +0 -1
  66. package/dist/types/datetime.js +0 -53
  67. package/dist/types/datetime.js.map +0 -1
  68. package/src/constants.ts +0 -5
  69. package/src/types/datetime.ts +0 -65
package/src/compiler.ts CHANGED
@@ -3,28 +3,52 @@ import {
3
3
  TypeCompiler,
4
4
  type ValueErrorIterator,
5
5
  } from '@sinclair/typebox/compiler'
6
- import { Value } from '@sinclair/typebox/value'
7
- import type { typeStatic } from './constants.ts'
8
- import { type BaseType, getTypeSchema } from './types/base.ts'
6
+ import {
7
+ TransformDecode,
8
+ TransformEncode,
9
+ Value,
10
+ } from '@sinclair/typebox/value'
11
+ import type { t } from './index.ts'
12
+ import { IsDiscriminatedUnion } from './schemas/discriminated-union.ts'
13
+ import type { BaseType } from './types/base.ts'
14
+
15
+ type ValidationError = {
16
+ path: string
17
+ message: string
18
+ value: unknown
19
+ }
9
20
 
10
21
  export type Compiled<T extends BaseType = BaseType> = {
11
22
  check: (val: unknown) => boolean
12
- errors: (val: unknown) => ValueErrorIterator
23
+ errors: (val: unknown) => ValidationError[]
13
24
  parse: (val: unknown) => unknown
14
- decode: (val: unknown) => T[typeStatic]['decoded']
15
- encode: (val: unknown) => T[typeStatic]['encoded']
25
+ /**
26
+ * Requires to `check` before calling
27
+ */
28
+ decode: (val: unknown) => t.infer.decoded<T>
29
+ /**
30
+ * Requires to `check` before calling
31
+ */
32
+ encode: (val: unknown) => t.infer.encoded<T>
33
+ /**
34
+ * Requires to `check` before calling
35
+ */
16
36
  decodeSafe: (
17
37
  val: unknown,
18
38
  ) =>
19
- | { success: true; value: T[typeStatic]['decoded'] }
39
+ | { success: true; value: t.infer.decoded<T> }
20
40
  | { success: false; error: any }
41
+ /**
42
+ * Requires to `check` before calling
43
+ */
21
44
  encodeSafe: (
22
45
  val: unknown,
23
46
  ) =>
24
- | { success: true; value: T[typeStatic]['encoded'] }
47
+ | { success: true; value: t.infer.encoded<T> }
25
48
  | { success: false; error: any }
26
49
  }
27
50
 
51
+ // FIXME: this one is very slow
28
52
  function _parse(schema: TSchema, value: any) {
29
53
  // Clone -> Clean -> Default -> Convert
30
54
  return Value.Convert(
@@ -33,70 +57,129 @@ function _parse(schema: TSchema, value: any) {
33
57
  )
34
58
  }
35
59
 
60
+ function _errors(errors: ValueErrorIterator) {
61
+ const result: ValidationError[] = []
62
+
63
+ for (const error of errors) {
64
+ if (IsDiscriminatedUnion(error.schema)) {
65
+ const discriminator = error.schema.discriminator
66
+ const discriminatorValue = error.value?.[discriminator]
67
+ if (discriminatorValue !== undefined) {
68
+ const variantSchema = error.schema.anyOf.find(
69
+ (schema) =>
70
+ schema.properties[discriminator].const === discriminatorValue,
71
+ )
72
+ if (variantSchema) {
73
+ const propertiesSchemas: TSchema[] = []
74
+ for (const element in variantSchema.properties) {
75
+ const propertySchema = variantSchema.properties[element]
76
+ if (propertySchema !== variantSchema.properties[discriminator]) {
77
+ propertiesSchemas.push(propertySchema)
78
+ }
79
+ }
80
+
81
+ for (const iter of error.errors) {
82
+ for (const err of iter) {
83
+ if (!propertiesSchemas.includes(err.schema)) continue
84
+ result.push({
85
+ path: err.path,
86
+ message: err.message,
87
+ value: err.value,
88
+ })
89
+ }
90
+ }
91
+
92
+ continue
93
+ }
94
+ }
95
+ }
96
+
97
+ result.push({
98
+ path: error.path,
99
+ message: error.message,
100
+ value: error.value,
101
+ })
102
+
103
+ for (const nestedError of error.errors) {
104
+ result.push(..._errors(nestedError))
105
+ }
106
+ }
107
+
108
+ return result
109
+ }
110
+
36
111
  function compileType(type: BaseType) {
37
- const schema = getTypeSchema(type)
112
+ const { final: schema } = type
38
113
  const compiled = TypeCompiler.Compile(schema)
114
+ const errors = (value) => {
115
+ return _errors(compiled.Errors(value))
116
+ }
117
+
39
118
  return {
40
119
  check: compiled.Check.bind(compiled),
41
- errors: compiled.Errors.bind(compiled),
42
- decode: compiled.Decode.bind(compiled),
43
- encode: compiled.Encode.bind(compiled),
44
120
  parse: _parse.bind(null, schema),
121
+ errors,
122
+ decode: TransformDecode.bind(null, schema, compiled.References()),
123
+ encode: TransformEncode.bind(null, schema, compiled.References()),
45
124
  }
46
125
  }
47
126
 
48
127
  export function compile<T extends BaseType>(schema: T): Compiled<T> {
49
128
  const compiled = compileType(schema)
50
129
 
51
- return {
52
- ...compiled,
53
- decodeSafe: (val) => {
54
- try {
55
- return {
56
- success: true as const,
57
- value: compiled.decode(val),
58
- }
59
- } catch (error) {
60
- return { success: false as const, error }
130
+ function decodeSafe(val: unknown) {
131
+ try {
132
+ return {
133
+ success: true as const,
134
+ value: compiled.decode(val),
61
135
  }
62
- },
63
- encodeSafe: (val) => {
64
- try {
65
- return {
66
- success: true as const,
67
- value: compiled.encode(val),
68
- }
69
- } catch (error) {
70
- return { success: false as const, error }
136
+ } catch (error) {
137
+ return { success: false as const, error }
138
+ }
139
+ }
140
+
141
+ function encodeSafe(val: unknown) {
142
+ try {
143
+ return {
144
+ success: true as const,
145
+ value: compiled.encode(val),
71
146
  }
72
- },
147
+ } catch (error) {
148
+ return { success: false as const, error }
149
+ }
73
150
  }
151
+
152
+ return {
153
+ ...compiled,
154
+ decodeSafe,
155
+ encodeSafe,
156
+ } as any
74
157
  }
75
158
 
76
159
  export namespace runtime {
77
160
  export function parse(type: BaseType, value: any) {
78
- return _parse(getTypeSchema(type), value)
161
+ return _parse(type.schema, value)
79
162
  }
80
163
 
81
- export function errors(type: BaseType, value: any): ValueErrorIterator {
82
- return Value.Errors(getTypeSchema(type), value)
164
+ export function errors(type: BaseType, value: any): ValidationError[] {
165
+ return _errors(Value.Errors(type.schema, value))
83
166
  }
84
167
 
85
168
  export function check(type: BaseType, value: any): boolean {
86
- return Value.Check(getTypeSchema(type), value)
169
+ return Value.Check(type.schema, value)
87
170
  }
88
171
 
89
172
  export function decode<T extends BaseType>(
90
- type: BaseType,
173
+ type: T,
91
174
  value: any,
92
- ): T[typeStatic]['decoded'] {
93
- return Value.Decode(getTypeSchema(type), value)
175
+ ): t.infer.decoded<T> {
176
+ return TransformDecode(type.schema, [], value)
94
177
  }
95
178
 
96
179
  export function encode<T extends BaseType>(
97
180
  type: T,
98
181
  value: any,
99
- ): T[typeStatic]['encoded'] {
100
- return Value.Encode(getTypeSchema(type), value)
182
+ ): t.infer.encoded<T> {
183
+ return TransformEncode(type.schema, [], value)
101
184
  }
102
185
  }
package/src/formats.ts CHANGED
@@ -32,7 +32,7 @@ export const fullFormats: Record<
32
32
  'iso-date-time': getDateTime(),
33
33
  // duration: https://tools.ietf.org/html/rfc3339#appendix-A
34
34
  duration:
35
- /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?((\d+|\d\.\d+)S)?)?|(\d+W)?)$/,
35
+ /^P(?!$)((\d+Y)?(\d+M)?(\d+D)?(T(?=\d)(\d+H)?(\d+M)?((\d+|\d+\.\d+)S)?)?|(\d+W)?)$/,
36
36
  uri,
37
37
  'uri-reference':
38
38
  /^(?:[a-z][a-z0-9+\-.]*:)?(?:\/?\/(?:(?:[a-z0-9\-._~!$&'()*+,;=:]|%[0-9a-f]{2})*@)?(?:\[(?:(?:(?:(?:[0-9a-f]{1,4}:){6}|::(?:[0-9a-f]{1,4}:){5}|(?:[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){4}|(?:(?:[0-9a-f]{1,4}:){0,1}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){3}|(?:(?:[0-9a-f]{1,4}:){0,2}[0-9a-f]{1,4})?::(?:[0-9a-f]{1,4}:){2}|(?:(?:[0-9a-f]{1,4}:){0,3}[0-9a-f]{1,4})?::[0-9a-f]{1,4}:|(?:(?:[0-9a-f]{1,4}:){0,4}[0-9a-f]{1,4})?::)(?:[0-9a-f]{1,4}:[0-9a-f]{1,4}|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?))|(?:(?:[0-9a-f]{1,4}:){0,5}[0-9a-f]{1,4})?::[0-9a-f]{1,4}|(?:(?:[0-9a-f]{1,4}:){0,6}[0-9a-f]{1,4})?::)|[Vv][0-9a-f]+\.[a-z0-9\-._~!$&'()*+,;=:]+)\]|(?:(?:25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(?:25[0-5]|2[0-4]\d|[01]?\d\d?)|(?:[a-z0-9\-._~!$&'"()*+,;=]|%[0-9a-f]{2})*)(?::\d*)?(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*|\/(?:(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?|(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})+(?:\/(?:[a-z0-9\-._~!$&'"()*+,;=:@]|%[0-9a-f]{2})*)*)?(?:\?(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?(?:#(?:[a-z0-9\-._~!$&'"()*+,;=:@/?]|%[0-9a-f]{2})*)?$/i,
package/src/index.ts CHANGED
@@ -1,38 +1,38 @@
1
- import type { TLiteralValue } from '@sinclair/typebox/type'
1
+ import type {
2
+ StaticDecode,
3
+ StaticEncode,
4
+ TLiteralValue,
5
+ } from '@sinclair/typebox/type'
6
+ import { AnyType } from './types/any.ts'
2
7
  import { ArrayType } from './types/array.ts'
3
- import type { BaseType } from './types/base.ts'
8
+ import type {
9
+ BaseType,
10
+ BaseTypeAny,
11
+ OptionalType,
12
+ Static,
13
+ } from './types/base.ts'
4
14
  import { BooleanType } from './types/boolean.ts'
5
15
  import { CustomType } from './types/custom.ts'
6
- import { DateType } from './types/datetime.ts'
7
- import {
8
- type AnyEnumType,
9
- type AnyObjectEnumType,
10
- EnumType,
11
- ObjectEnumType,
12
- } from './types/enum.ts'
13
- import { type AnyLiteralType, LiteralType } from './types/literal.ts'
16
+ import { DateType } from './types/date.ts'
17
+ import { EnumType, ObjectEnumType } from './types/enum.ts'
18
+ import { LiteralType } from './types/literal.ts'
19
+ import { NeverType } from './types/never.ts'
14
20
  import { BigIntType, IntegerType, NumberType } from './types/number.ts'
15
- import { ObjectType, RecordType } from './types/object.ts'
16
- import { type AnyStringType, StringType } from './types/string.ts'
21
+ import { ObjectType, type ObjectTypeProps, RecordType } from './types/object.ts'
22
+ import { StringType } from './types/string.ts'
17
23
  import {
18
- type AnyUnionType,
24
+ DiscriminatedUnionType,
19
25
  IntersactionType,
20
26
  UnionType,
21
27
  } from './types/union.ts'
22
-
23
- import type { typeStatic } from './constants.ts'
24
- import { AnyType } from './types/any.ts'
25
- import { NeverType } from './types/never.ts'
28
+ import type { UnionToTupleString } from './utils.ts'
26
29
 
27
30
  // register ajv formats
28
31
  import { register } from './formats.ts'
29
32
  register()
30
33
 
31
34
  export * from './schemas/nullable.ts'
32
- export {
33
- BaseType,
34
- getTypeSchema,
35
- } from './types/base.ts'
35
+ export { BaseType, type BaseTypeAny } from './types/base.ts'
36
36
  export { type TSchema } from '@sinclair/typebox'
37
37
  export {
38
38
  ArrayType,
@@ -53,48 +53,130 @@ export {
53
53
 
54
54
  export namespace t {
55
55
  export namespace infer {
56
- export type staticType<T extends BaseType> = T[typeStatic]
57
- export type decoded<T extends BaseType> = staticType<T>['decoded']
58
- export type encoded<T extends BaseType> = staticType<T>['encoded']
56
+ export type decoded<T extends BaseTypeAny> = StaticDecode<
57
+ T['_']['decoded']['output']
58
+ >
59
+ export type encoded<T extends BaseTypeAny> = StaticEncode<
60
+ T['_']['encoded']['output']
61
+ >
62
+ export namespace input {
63
+ export type decoded<T extends BaseTypeAny> = StaticDecode<
64
+ T['_']['decoded']['input']
65
+ >
66
+ export type encoded<T extends BaseTypeAny> = StaticEncode<
67
+ T['_']['encoded']['input']
68
+ >
69
+ }
70
+ }
71
+
72
+ export const never = NeverType.factory
73
+ export const boolean = BooleanType.factory
74
+ export const string = StringType.factory
75
+ export const number = NumberType.factory
76
+ export const integer = IntegerType.factory
77
+ export const bitint = BigIntType.factory
78
+ export const literal = LiteralType.factory
79
+ export const objectEnum = ObjectEnumType.factory
80
+ export const arrayEnum = EnumType.factory
81
+ export const date = DateType.factory
82
+ export const array = ArrayType.factory
83
+ export const object = ObjectType.factory
84
+ export const record = RecordType.factory
85
+ export const any = AnyType.factory
86
+ export const or = UnionType.factory
87
+ export const and = IntersactionType.factory
88
+ export const discriminatedUnion = DiscriminatedUnionType.factory
89
+ export const custom = CustomType.factory
90
+
91
+ export const keyof = <T extends ObjectType>(
92
+ type: T,
93
+ ): EnumType<
94
+ UnionToTupleString<T extends ObjectType<infer Props> ? keyof Props : never>
95
+ > => {
96
+ return arrayEnum(Object.keys(type.props.properties) as any)
59
97
  }
60
- export const never = () => new NeverType()
61
- export const boolean = () => new BooleanType()
62
- export const string = () => new StringType()
63
- export const number = () => new NumberType()
64
- export const integer = () => new IntegerType()
65
- export const bitint = () => new BigIntType()
66
- export const literal = <T extends TLiteralValue>(value: T) =>
67
- new LiteralType(value)
68
- export const objectEnum = <T extends { [K in string]: K }>(enumLike: T) =>
69
- new ObjectEnumType(enumLike)
70
- export const arrayEnum = <T extends (string | number)[]>(enumLike: [...T]) =>
71
- new EnumType(enumLike)
72
- export const date = () => new DateType()
73
- export const array = <T extends BaseType>(element: T) =>
74
- new ArrayType(element)
75
- export const object = <T extends Record<string, BaseType>>(properties: T) =>
76
- new ObjectType(properties)
77
- export const record = <
78
- K extends
79
- | AnyLiteralType
80
- | AnyEnumType
81
- | AnyObjectEnumType
82
- | AnyStringType
83
- | AnyUnionType,
84
- E extends BaseType,
98
+
99
+ export const pick = <
100
+ T extends ObjectType,
101
+ P extends { [K in keyof T['props']['properties']]?: true },
85
102
  >(
86
- key: K,
87
- value: E,
88
- ) => new RecordType(key, value)
89
- export const any = () => new AnyType()
90
- export const or = <T extends [BaseType, BaseType, ...BaseType[]]>(
91
- ...types: T
92
- ) => new UnionType(types)
93
- export const and = <T extends [BaseType, BaseType, ...BaseType[]]>(
94
- ...types: T
95
- ) => new IntersactionType(types)
96
- export const custom = <T>(
97
- decode: (value: any) => T,
98
- encode: (value: T) => any,
99
- ) => new CustomType<T>(decode, encode)
103
+ source: T,
104
+ pick: P,
105
+ ): ObjectType<{
106
+ [K in keyof T['props']['properties'] as K extends keyof P
107
+ ? K
108
+ : never]: T['props']['properties'][K]
109
+ }> => {
110
+ const properties = Object.fromEntries(
111
+ Object.entries(source.props.properties).filter(([key]) => pick[key]),
112
+ )
113
+ return ObjectType.factory(properties) as any
114
+ }
115
+
116
+ export const omit = <
117
+ T extends ObjectType,
118
+ P extends { [K in keyof T]?: true },
119
+ >(
120
+ source: T,
121
+ omit: P,
122
+ ): ObjectType<{
123
+ [K in keyof T['props']['properties'] as K extends keyof P
124
+ ? never
125
+ : K]: T['props']['properties'][K]
126
+ }> => {
127
+ const properties = Object.fromEntries(
128
+ Object.entries(source.props.properties).filter(([key]) => !omit[key]),
129
+ )
130
+ return ObjectType.factory(properties) as any
131
+ }
132
+
133
+ export const extend = <T extends ObjectType, P extends ObjectTypeProps>(
134
+ object1: T,
135
+ properties: P,
136
+ ): ObjectType<{
137
+ [K in keyof T['props']['properties'] | keyof P]: K extends keyof P
138
+ ? P[K]
139
+ : K extends keyof T['props']['properties']
140
+ ? T['props']['properties'][K]
141
+ : never
142
+ }> => {
143
+ return ObjectType.factory({
144
+ ...object1.props.properties,
145
+ ...properties,
146
+ }) as any
147
+ }
148
+
149
+ export const merge = <T1 extends ObjectType, T2 extends ObjectType>(
150
+ object1: T1,
151
+ object2: T2,
152
+ ): ObjectType<{
153
+ [K in
154
+ | keyof T1['props']['properties']
155
+ | keyof T2['props']['properties']]: K extends keyof T2['props']['properties']
156
+ ? T2['props']['properties'][K]
157
+ : K extends keyof T1['props']['properties']
158
+ ? T1['props']['properties'][K]
159
+ : never
160
+ }> => {
161
+ return ObjectType.factory({
162
+ ...object1.props.properties,
163
+ ...object2.props.properties,
164
+ }) as any
165
+ }
166
+
167
+ export const partial = <T extends ObjectType>(
168
+ object: T,
169
+ ): ObjectType<{
170
+ [K in keyof T['props']['properties']]: OptionalType<
171
+ T['props']['properties'][K]
172
+ >
173
+ }> => {
174
+ const properties = {} as any
175
+
176
+ for (const [key, value] of Object.entries(object.props.properties)) {
177
+ properties[key] = value.optional()
178
+ }
179
+
180
+ return ObjectType.factory(properties, {}) as any
181
+ }
100
182
  }
@@ -0,0 +1,49 @@
1
+ import {
2
+ KindGuard,
3
+ type TLiteral,
4
+ type TObject,
5
+ type TPropertyKey,
6
+ type TSchema,
7
+ type TUnion,
8
+ Type,
9
+ TypeGuard,
10
+ ValueGuard,
11
+ } from '@sinclair/typebox'
12
+
13
+ export function IsDiscriminatedUnion(
14
+ schema: TSchema,
15
+ ): schema is TDiscriminatedUnion {
16
+ return (
17
+ TypeGuard.IsUnion(schema) &&
18
+ 'discriminator' in schema &&
19
+ ValueGuard.IsString(schema.discriminator) &&
20
+ schema.anyOf.every(
21
+ (variant) =>
22
+ KindGuard.IsObject(variant) &&
23
+ KindGuard.IsLiteralString(variant.properties[schema.discriminator]),
24
+ )
25
+ )
26
+ }
27
+
28
+ type DiscriminatedUnionProperties<K extends string = string> = {
29
+ [OK in K]: TLiteral<any>
30
+ } & {
31
+ [OK in TPropertyKey]: any
32
+ }
33
+
34
+ export interface TDiscriminatedUnion<
35
+ K extends string = string,
36
+ T extends TObject<DiscriminatedUnionProperties<K>>[] = TObject<
37
+ DiscriminatedUnionProperties<K>
38
+ >[],
39
+ > extends TUnion<T> {
40
+ discriminator: K
41
+ anyOf: T
42
+ }
43
+
44
+ export function DiscriminatedUnion<
45
+ K extends string,
46
+ T extends TObject<DiscriminatedUnionProperties<K>>[],
47
+ >(key: K, types: T): TDiscriminatedUnion<K, T> {
48
+ return Type.Union(types, { discriminator: key }) as any
49
+ }
@@ -1,7 +1,9 @@
1
1
  import {
2
2
  type SchemaOptions,
3
3
  type TNull,
4
+ type TOptional,
4
5
  type TSchema,
6
+ type TUndefined,
5
7
  type TUnion,
6
8
  Type,
7
9
  } from '@sinclair/typebox/type'
@@ -11,22 +13,14 @@ export const Nullable = <T extends TSchema>(
11
13
  schema: T,
12
14
  options: SchemaOptions = {},
13
15
  ) => {
14
- const {
15
- default: _default,
16
- description,
17
- examples,
18
- readOnly,
19
- title,
20
- writeOnly,
21
- } = schema
16
+ const { default: _default } = schema
22
17
 
23
18
  return Type.Union([schema, Type.Null()], {
24
19
  default: _default,
25
- description,
26
- examples,
27
- readOnly,
28
- title,
29
- writeOnly,
30
20
  ...options,
31
21
  })
32
22
  }
23
+
24
+ export type TOptionalUndefined<T extends TSchema> = TOptional<
25
+ TUnion<[T, TUndefined]>
26
+ >
package/src/temporal.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { Temporal } from 'temporal-polyfill'
1
2
  import {
2
3
  DurationType,
3
4
  PlainDateTimeType,
@@ -8,13 +9,13 @@ import {
8
9
  ZonedDateTimeType,
9
10
  } from './types/temporal.ts'
10
11
 
11
- export const plainDate = () => new PlainDateType()
12
- export const plainDatetime = () => new PlainDateTimeType()
13
- export const plainTime = () => new PlainTimeType()
14
- export const zonedDatetime = () => new ZonedDateTimeType()
15
- export const duration = () => new DurationType()
16
- export const plainYearMonth = () => new PlainYearMonthType()
17
- export const plainMonthDay = () => new PlainMonthDayType()
12
+ export const plainDate = PlainDateType.factory
13
+ export const plainDatetime = PlainDateTimeType.factory
14
+ export const plainTime = PlainTimeType.factory
15
+ export const zonedDatetime = ZonedDateTimeType.factory
16
+ export const duration = DurationType.factory
17
+ export const plainYearMonth = PlainYearMonthType.factory
18
+ export const plainMonthDay = PlainMonthDayType.factory
18
19
 
19
20
  export {
20
21
  DurationType,
package/src/types/any.ts CHANGED
@@ -1,50 +1,10 @@
1
- import { type SchemaOptions, type TAny, Type } from '@sinclair/typebox'
2
- import { BaseType } from './base.ts'
1
+ import { type TAny, Type } from '@sinclair/typebox'
2
+ import { BaseType, type ConstantType } from './base.ts'
3
3
 
4
- export class AnyType<
5
- N extends boolean = false,
6
- O extends boolean = false,
7
- D extends boolean = false,
8
- > extends BaseType<TAny, N, O, D, SchemaOptions> {
9
- constructor(
10
- options: SchemaOptions = {},
11
- isNullable: N = false as N,
12
- isOptional: O = false as O,
13
- hasDefault: D = false as D,
14
- ) {
15
- super(options, isNullable, isOptional, hasDefault)
16
- }
17
-
18
- protected _constructSchema(options: SchemaOptions): TAny {
19
- return Type.Any(options)
20
- }
21
-
22
- nullable() {
23
- return new AnyType(...this._with({ isNullable: true }))
24
- }
25
-
26
- optional() {
27
- return new AnyType(...this._with({ isOptional: true }))
28
- }
29
-
30
- nullish() {
31
- return new AnyType(...this._with({ isNullable: true, isOptional: true }))
32
- }
33
-
34
- default(value: any) {
35
- return new AnyType(
36
- ...this._with({
37
- options: { default: value },
38
- hasDefault: true,
39
- }),
40
- )
41
- }
42
-
43
- description(description: string) {
44
- return new AnyType(...this._with({ options: { description } }))
45
- }
4
+ export class AnyType extends BaseType<TAny> {
5
+ _!: ConstantType<this['schema']>
46
6
 
47
- examples(...examples: [any, ...any[]]) {
48
- return new AnyType(...this._with({ options: { examples } }))
7
+ static factory() {
8
+ return new AnyType(Type.Any())
49
9
  }
50
10
  }