@oh-my-pi/omptype 17.2.7 → 17.2.9

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.
package/src/typebox.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { OmpTypeError } from "./errors";
2
- import type { Def } from "./ir";
3
- import { type NarrowContext, type Type as OmpType, type } from "./type";
2
+ import type { Def, EmbeddableSchema } from "./ir";
3
+ import { type NarrowContext, type Type as OmpType, type ToJsonSchemaOptions, type } from "./type";
4
4
 
5
5
  export interface Meta {
6
6
  title?: string;
@@ -32,7 +32,7 @@ export interface ArrayOpts extends Meta {
32
32
  }
33
33
 
34
34
  export interface ObjectOpts extends Meta {
35
- additionalProperties?: boolean | TSchema;
35
+ additionalProperties?: boolean | AnySchema;
36
36
  }
37
37
  const OPTIONAL_INNER = Symbol("omptype.typebox.optionalInner");
38
38
  const OBJECT_INFO = Symbol("omptype.typebox.objectInfo");
@@ -52,53 +52,84 @@ interface LegacyTypeBoxCompat<T> {
52
52
  safeParse(input: unknown): TypeBoxSafeParseResult<T>;
53
53
  }
54
54
 
55
- export type TSchema<T = unknown> = OmpType<T> & LegacyTypeBoxCompat<T>;
56
- export type Static<T extends TSchema> = T["infer"];
57
- export type TAny = TSchema<unknown>;
58
- export type TUnknown = TSchema<unknown>;
59
- export type TNever = TSchema<never>;
60
- export type TNull = TSchema<null>;
61
- export type TString = TSchema<string>;
62
- export type TNumber = TSchema<number>;
63
- export type TInteger = TSchema<number>;
64
- export type TBoolean = TSchema<boolean>;
65
- export type TLiteral<V extends string | number | boolean | null> = TSchema<V>;
66
- export type TArray<E extends TSchema> = TSchema<Static<E>[]>;
67
- export type TTuple<E extends readonly TSchema[] = readonly TSchema[]> = TSchema<{
55
+ /**
56
+ * Erased schema surface accepted anywhere this facade takes a schema, native
57
+ * omptype schemas included (those carry no legacy compat members).
58
+ *
59
+ * Members use method syntax so parameter positions stay bivariant: the typed
60
+ * {@link TTyped} form is invariant in its static type (its `in`/`out`
61
+ * validators are), so a concrete `TString` is not assignable to
62
+ * `TTyped<unknown>`. Erasing here is what keeps `TString`, `TObject<…>` and
63
+ * friends assignable to a plain schema annotation.
64
+ */
65
+ export interface AnySchema extends EmbeddableSchema {
66
+ (data: unknown): unknown;
67
+ readonly infer: unknown;
68
+ readonly hasSteps: boolean;
69
+ toJsonSchema(options?: ToJsonSchemaOptions): Record<string, unknown>;
70
+ }
71
+
72
+ /**
73
+ * Every schema this facade returns: the TypeBox `TSchema` analog. Erased like
74
+ * {@link AnySchema}, plus the legacy compat members builder results carry.
75
+ */
76
+ export interface TSchema extends AnySchema {
77
+ /** TypeBox compatibility validator used by legacy extension loaders. */
78
+ __validator(data: unknown): unknown;
79
+ /** Zod-style compatibility parser used by legacy extensions. */
80
+ safeParse(input: unknown): TypeBoxSafeParseResult<unknown>;
81
+ }
82
+
83
+ /** Schema carrying a statically known type; every `TXxx` alias resolves here. */
84
+ export type TTyped<T> = OmpType<T> & LegacyTypeBoxCompat<T>;
85
+ export type Static<T extends AnySchema> = T["infer"];
86
+ export type TAny = TTyped<unknown>;
87
+ export type TUnknown = TTyped<unknown>;
88
+ export type TNever = TTyped<never>;
89
+ export type TNull = TTyped<null>;
90
+ export type TString = TTyped<string>;
91
+ export type TNumber = TTyped<number>;
92
+ export type TInteger = TTyped<number>;
93
+ export type TBoolean = TTyped<boolean>;
94
+ export type TLiteral<V extends string | number | boolean | null> = TTyped<V>;
95
+ export type TArray<E extends AnySchema> = TTyped<Static<E>[]>;
96
+ export type TTuple<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<{
68
97
  -readonly [K in keyof E]: Static<E[K]>;
69
98
  }>;
70
- export type TOptional<E extends TSchema> = TSchema<Static<E> | undefined> & { readonly [OPTIONAL_INNER]: E };
71
- export type TUnion<E extends readonly TSchema[] = readonly TSchema[]> = TSchema<Static<E[number]>>;
72
- export type TIntersect<E extends readonly TSchema[] = readonly TSchema[]> = TSchema<
99
+ export type TOptional<E extends AnySchema> = TTyped<Static<E> | undefined> & { readonly [OPTIONAL_INNER]: E };
100
+ export type TUnion<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<Static<E[number]>>;
101
+ export type TIntersect<E extends readonly AnySchema[] = readonly AnySchema[]> = TTyped<
73
102
  UnionToIntersection<Static<E[number]>>
74
103
  >;
75
- export type TEnum<E extends readonly (string | number)[] = readonly (string | number)[]> = TSchema<E[number]>;
76
- export type TRecord<K extends TSchema, V extends TSchema> = TSchema<Record<Extract<Static<K>, PropertyKey>, Static<V>>>;
77
- export type TNullable<E extends TSchema> = TSchema<Static<E> | null>;
78
- export type TReadonly<E extends TSchema> = TSchema<Readonly<Static<E>>>;
79
- export type TUnsafe<T = unknown> = TSchema<T>;
80
-
81
- type OptionalKeys<P extends Record<string, TSchema>> = {
82
- [K in keyof P]-?: P[K] extends { readonly [OPTIONAL_INNER]: TSchema } ? K : never;
104
+ export type TEnum<E extends readonly (string | number)[] = readonly (string | number)[]> = TTyped<E[number]>;
105
+ export type TRecord<K extends AnySchema, V extends AnySchema> = TTyped<
106
+ Record<Extract<Static<K>, PropertyKey>, Static<V>>
107
+ >;
108
+ export type TNullable<E extends AnySchema> = TTyped<Static<E> | null>;
109
+ export type TReadonly<E extends AnySchema> = TTyped<Readonly<Static<E>>>;
110
+ export type TUnsafe<T = unknown> = TTyped<T>;
111
+
112
+ type OptionalKeys<P extends Record<string, AnySchema>> = {
113
+ [K in keyof P]-?: P[K] extends { readonly [OPTIONAL_INNER]: AnySchema } ? K : never;
83
114
  }[keyof P];
84
- type RequiredKeys<P extends Record<string, TSchema>> = Exclude<keyof P, OptionalKeys<P>>;
85
- type ObjectStatic<P extends Record<string, TSchema>> = {
115
+ type RequiredKeys<P extends Record<string, AnySchema>> = Exclude<keyof P, OptionalKeys<P>>;
116
+ type ObjectStatic<P extends Record<string, AnySchema>> = {
86
117
  [K in RequiredKeys<P>]: Static<P[K]>;
87
118
  } & {
88
119
  [K in OptionalKeys<P>]?: Exclude<Static<P[K]>, undefined>;
89
120
  };
90
- export type TObject<P extends Record<string, TSchema> = Record<string, TSchema>> = TSchema<ObjectStatic<P>>;
91
- type RequiredProps<P extends Record<string, TSchema>> = {
121
+ export type TObject<P extends Record<string, AnySchema> = Record<string, AnySchema>> = TTyped<ObjectStatic<P>>;
122
+ type RequiredProps<P extends Record<string, AnySchema>> = {
92
123
  [K in keyof P]: P[K] extends TOptional<infer E> ? E : P[K];
93
124
  };
94
125
 
95
126
  interface RuntimeType<T> extends OmpType<T> {
96
- [OPTIONAL_INNER]?: TSchema;
127
+ [OPTIONAL_INNER]?: AnySchema;
97
128
  [OBJECT_INFO]?: ObjectInfo;
98
129
  describe(description: string): RuntimeType<T>;
99
130
  default(value: T | (() => T)): RuntimeType<T>;
100
- or<R>(schema: OmpType<R>): RuntimeType<T | R>;
101
- and<R>(schema: OmpType<R>): RuntimeType<T & R>;
131
+ or<schema extends AnySchema>(schema: schema): RuntimeType<T | Static<schema>>;
132
+ and<schema extends AnySchema>(schema: schema): RuntimeType<T & Static<schema>>;
102
133
  array(): RuntimeType<T[]>;
103
134
  atLeastLength(bound: number): RuntimeType<T>;
104
135
  atMostLength(bound: number): RuntimeType<T>;
@@ -109,7 +140,18 @@ interface RuntimeType<T> extends OmpType<T> {
109
140
  }
110
141
  type CompatRuntime<T> = RuntimeType<T> & LegacyTypeBoxCompat<T>;
111
142
 
112
- type ObjectInfo = { props: Record<string, TSchema>; additionalProperties?: boolean | TSchema };
143
+ type ObjectInfo = {
144
+ props: Record<string, AnySchema>;
145
+ additionalProperties?: boolean | AnySchema;
146
+ };
147
+
148
+ function asRuntime<T>(schema: AnySchema): RuntimeType<T> {
149
+ return schema as unknown as RuntimeType<T>;
150
+ }
151
+
152
+ function asSchema<T>(schema: AnySchema): TTyped<T> {
153
+ return schema as unknown as TTyped<T>;
154
+ }
113
155
 
114
156
  function validationFailure(message: string): TypeBoxValidationFailure {
115
157
  return { message };
@@ -161,9 +203,7 @@ function checkFiniteOption(name: string, value: number | undefined): void {
161
203
  function tString(opts?: StringOpts): TString {
162
204
  checkFiniteOption("minLength", opts?.minLength);
163
205
  checkFiniteOption("maxLength", opts?.maxLength);
164
- let schema = type.raw(
165
- opts?.format === "url" || opts?.format === "uri" ? "string.url" : "string",
166
- ) as RuntimeType<string>;
206
+ let schema = asRuntime<string>(type.raw(opts?.format === "url" || opts?.format === "uri" ? "string.url" : "string"));
167
207
  if (opts?.minLength !== undefined) schema = schema.atLeastLength(opts.minLength);
168
208
  if (opts?.maxLength !== undefined) schema = schema.atMostLength(opts.maxLength);
169
209
  if (opts?.pattern !== undefined) {
@@ -227,9 +267,19 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
227
267
  upper = { value: opts.exclusiveMaximum, exclusive: true };
228
268
  }
229
269
  const keyword = integer ? "number.integer" : "number";
230
- const lowerDsl = lower ? `${lower.value} ${lower.exclusive ? "<" : "<="} ` : "";
231
- const upperDsl = upper ? ` ${upper.exclusive ? "<" : "<="} ${upper.value}` : "";
232
- let schema = type.raw(`${lowerDsl}${keyword}${upperDsl}`) as RuntimeType<number>;
270
+ // The `LO <= TYPE <= HI` range spelling requires both bounds; a min-only
271
+ // bound must use the postfix `TYPE >= LO` form (see parseBounded in ir.ts).
272
+ let src: string;
273
+ if (lower && upper) {
274
+ src = `${lower.value} ${lower.exclusive ? "<" : "<="} ${keyword} ${upper.exclusive ? "<" : "<="} ${upper.value}`;
275
+ } else if (lower) {
276
+ src = `${keyword} ${lower.exclusive ? ">" : ">="} ${lower.value}`;
277
+ } else if (upper) {
278
+ src = `${keyword} ${upper.exclusive ? "<" : "<="} ${upper.value}`;
279
+ } else {
280
+ src = keyword;
281
+ }
282
+ let schema = asRuntime<number>(type.raw(src));
233
283
  if (opts?.multipleOf !== undefined) {
234
284
  const divisor = opts.multipleOf;
235
285
  schema = schema.narrow((value, ctx) => {
@@ -244,33 +294,32 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
244
294
  }
245
295
 
246
296
  function tLiteral<const V extends string | number | boolean | null>(value: V, opts?: Meta): TLiteral<V> {
247
- return applyMeta(type.enumerated(value) as RuntimeType<V>, opts);
297
+ return applyMeta(asRuntime<V>(type.enumerated(value)), opts);
248
298
  }
249
299
 
250
300
  function tNever(opts?: Meta): TNever {
251
301
  return applyMeta(
252
- (type.raw("unknown") as RuntimeType<unknown>).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
302
+ asRuntime<unknown>(type.raw("unknown")).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
253
303
  opts,
254
304
  );
255
305
  }
256
306
 
257
- function tUnion<const E extends readonly TSchema[]>(schemas: E, opts?: Meta): TUnion<E> {
258
- if (schemas.length === 0) return tNever(opts) as TUnion<E>;
259
- let result = schemas[0] as unknown as RuntimeType<unknown>;
307
+ function tUnion<const E extends readonly AnySchema[]>(schemas: E, opts?: Meta): TUnion<E> {
308
+ if (schemas.length === 0) return asSchema<Static<E[number]>>(tNever(opts));
309
+ let result = asRuntime<unknown>(schemas[0]);
260
310
  for (let i = 1; i < schemas.length; i++) result = result.or(schemas[i]);
261
- return applyMeta(result, opts) as TUnion<E>;
311
+ return asSchema<Static<E[number]>>(applyMeta(result, opts));
262
312
  }
263
313
 
264
- function tIntersect<const E extends readonly TSchema[]>(
314
+ function tIntersect<const E extends readonly AnySchema[]>(
265
315
  schemas: E,
266
316
  opts?: Meta,
267
- ): TSchema<UnionToIntersection<Static<E[number]>>> {
268
- if (schemas.length === 0)
269
- return applyMeta(type.raw("unknown") as RuntimeType<unknown>, opts) as TSchema<
270
- UnionToIntersection<Static<E[number]>>
271
- >;
317
+ ): TTyped<UnionToIntersection<Static<E[number]>>> {
318
+ if (schemas.length === 0) {
319
+ return applyMeta(asRuntime<UnionToIntersection<Static<E[number]>>>(type.raw("unknown")), opts);
320
+ }
272
321
  const validateAll = (): RuntimeType<UnionToIntersection<Static<E[number]>>> => {
273
- const base = type.raw("unknown") as RuntimeType<unknown>;
322
+ const base = asRuntime<unknown>(type.raw("unknown"));
274
323
  return base.narrow((value, ctx): value is UnionToIntersection<Static<E[number]>> => {
275
324
  for (const schema of schemas) {
276
325
  if (schema(value) instanceof type.errors) return ctx.mustBe("a value satisfying every intersection member");
@@ -279,14 +328,14 @@ function tIntersect<const E extends readonly TSchema[]>(
279
328
  });
280
329
  };
281
330
  if (schemas.some(schema => schema.hasSteps)) return applyMeta(validateAll(), opts);
282
- let result = schemas[0] as unknown as RuntimeType<unknown>;
331
+ let result = asRuntime<unknown>(schemas[0]);
283
332
  try {
284
333
  for (let i = 1; i < schemas.length; i++) result = result.and(schemas[i]);
285
334
  } catch (error) {
286
335
  if (error instanceof OmpTypeError) return applyMeta(validateAll(), opts);
287
336
  throw error;
288
337
  }
289
- return applyMeta(result, opts) as TSchema<UnionToIntersection<Static<E[number]>>>;
338
+ return asSchema<UnionToIntersection<Static<E[number]>>>(applyMeta(result, opts));
290
339
  }
291
340
  type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void
292
341
  ? I
@@ -306,16 +355,17 @@ function enumValues(values: Record<string, string | number> | readonly (string |
306
355
  function tEnum<const E extends Record<string, string | number> | readonly (string | number)[]>(
307
356
  values: E,
308
357
  opts?: Meta,
309
- ): TSchema<E extends readonly (infer V)[] ? V : E[keyof E]> {
310
- return applyMeta(type.enumerated(...enumValues(values)) as RuntimeType<string | number>, opts) as unknown as TSchema<
311
- E extends readonly (infer V)[] ? V : E[keyof E]
312
- >;
358
+ ): TTyped<E extends readonly (infer V)[] ? V : E[keyof E]> {
359
+ return applyMeta(
360
+ asRuntime<E extends readonly (infer V)[] ? V : E[keyof E]>(type.enumerated(...enumValues(values))),
361
+ opts,
362
+ );
313
363
  }
314
364
 
315
- function tArray<E extends TSchema>(item: E, opts?: ArrayOpts): TArray<E> {
365
+ function tArray<E extends AnySchema>(item: E, opts?: ArrayOpts): TArray<E> {
316
366
  checkFiniteOption("minItems", opts?.minItems);
317
367
  checkFiniteOption("maxItems", opts?.maxItems);
318
- let schema = (item as unknown as RuntimeType<Static<E>>).array();
368
+ let schema = asRuntime<Static<E>>(item).array();
319
369
  if (opts?.minItems !== undefined) schema = schema.atLeastLength(opts.minItems);
320
370
  if (opts?.maxItems !== undefined) schema = schema.atMostLength(opts.maxItems);
321
371
  if (opts?.uniqueItems) {
@@ -342,8 +392,8 @@ function jsonEqual(left: unknown, right: unknown): boolean {
342
392
  }
343
393
  }
344
394
 
345
- function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTuple<E> {
346
- const schema = (type.raw("unknown") as RuntimeType<unknown>).narrow(
395
+ function tTuple<const E extends readonly AnySchema[]>(items: E, opts?: Meta): TTuple<E> {
396
+ const schema = asRuntime<unknown>(type.raw("unknown")).narrow(
347
397
  (value, ctx): value is { -readonly [K in keyof E]: Static<E[K]> } => {
348
398
  if (!Array.isArray(value) || value.length !== items.length)
349
399
  return ctx.mustBe(`a tuple of length ${items.length}`);
@@ -355,25 +405,29 @@ function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTup
355
405
  return applyMeta(schema, opts);
356
406
  }
357
407
 
358
- function tObject<const P extends Record<string, TSchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
408
+ function tObject<const P extends Record<string, AnySchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
359
409
  const def: Record<string, Def> = {};
360
- const props: Record<string, TSchema> = {};
410
+ const props: Record<string, AnySchema> = {};
361
411
  for (const key in properties) {
362
412
  const schema = properties[key];
363
- const inner = (schema as unknown as RuntimeType<unknown>)[OPTIONAL_INNER];
364
- def[inner ? `${key}?` : key] = (inner ?? schema) as Def;
413
+ const inner = asRuntime<unknown>(schema)[OPTIONAL_INNER];
414
+ // A defaulted `Type.Optional(...)` maps to a plain defaulted key:
415
+ // omptype (like ArkType) rejects `key?` with a default, and a default
416
+ // already makes the key omittable on input.
417
+ const optionalKey = inner !== undefined && !asRuntime<unknown>(inner).hasDefault;
418
+ def[optionalKey ? `${key}?` : key] = inner ?? schema;
365
419
  props[key] = schema;
366
420
  }
367
421
  if (opts?.additionalProperties === false) def["+"] = "reject";
368
422
  else if (opts?.additionalProperties && opts.additionalProperties !== true)
369
- def["[string]"] = opts.additionalProperties as Def;
370
- const schema = applyMeta(type.raw(def) as RuntimeType<ObjectStatic<P>>, opts);
423
+ def["[string]"] = opts.additionalProperties;
424
+ const schema = applyMeta(asRuntime<ObjectStatic<P>>(type.raw(def)), opts);
371
425
  schema[OBJECT_INFO] = { props, additionalProperties: opts?.additionalProperties };
372
426
  return schema;
373
427
  }
374
428
 
375
- function tRecord<K extends TSchema, V extends TSchema>(key: K, value: V, opts?: Meta): TRecord<K, V> {
376
- const base = (type.raw({ "[string]": value }) as RuntimeType<Record<string, Static<V>>>).narrow((record, ctx) => {
429
+ function tRecord<K extends AnySchema, V extends AnySchema>(key: K, value: V, opts?: Meta): TRecord<K, V> {
430
+ const base = asRuntime<Record<string, Static<V>>>(type.raw({ "[string]": value })).narrow((record, ctx) => {
377
431
  for (const name in record)
378
432
  if (key(name) instanceof type.errors) return ctx.mustBe("an object with valid record keys");
379
433
  return true;
@@ -381,72 +435,70 @@ function tRecord<K extends TSchema, V extends TSchema>(key: K, value: V, opts?:
381
435
  return applyMeta(base, opts) as TRecord<K, V>;
382
436
  }
383
437
 
384
- function tOptional<E extends TSchema>(schema: E, opts?: Meta): TOptional<E> {
438
+ function tOptional<E extends AnySchema>(schema: E, opts?: Meta): TOptional<E> {
385
439
  const marker = applyMeta(
386
- (schema as unknown as RuntimeType<Static<E>>).or(type.raw("undefined")),
440
+ asRuntime<Static<E>>(schema).or(asRuntime<undefined>(type.raw("undefined"))),
387
441
  opts,
388
442
  ) as RuntimeType<Static<E> | undefined>;
389
443
  marker[OPTIONAL_INNER] = schema;
390
444
  return marker as unknown as TOptional<E>;
391
445
  }
392
446
 
393
- function tNullable<E extends TSchema>(schema: E, opts?: Meta): TSchema<Static<E> | null> {
394
- return applyMeta((schema as unknown as RuntimeType<Static<E>>).or(type.raw("null")), opts);
447
+ function tNullable<E extends AnySchema>(schema: E, opts?: Meta): TTyped<Static<E> | null> {
448
+ return applyMeta(asRuntime<Static<E>>(schema).or(asRuntime<null>(type.raw("null"))), opts);
395
449
  }
396
450
 
397
- function requireObject(schema: TSchema, operation: string): ObjectInfo {
398
- const info = (schema as unknown as RuntimeType<unknown>)[OBJECT_INFO];
451
+ function requireObject(schema: AnySchema, operation: string): ObjectInfo {
452
+ const info = asRuntime<unknown>(schema)[OBJECT_INFO];
399
453
  if (!info) throw new OmpTypeError(`Type.${operation} requires a schema created by Type.Object`);
400
454
  return info;
401
455
  }
402
456
 
403
- function tPartial<P extends Record<string, TSchema>>(schema: TObject<P>): TSchema<Partial<ObjectStatic<P>>> {
457
+ function tPartial<P extends Record<string, AnySchema>>(schema: TObject<P>): TTyped<Partial<ObjectStatic<P>>> {
404
458
  const info = requireObject(schema, "Partial");
405
- const props: Record<string, TSchema> = {};
459
+ const props: Record<string, AnySchema> = {};
406
460
  for (const key in info.props)
407
- props[key] = (info.props[key] as unknown as RuntimeType<unknown>)[OPTIONAL_INNER]
408
- ? info.props[key]
409
- : tOptional(info.props[key]);
410
- return tObject(props, { additionalProperties: info.additionalProperties }) as TSchema<Partial<ObjectStatic<P>>>;
461
+ props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ? info.props[key] : tOptional(info.props[key]);
462
+ return tObject(props, { additionalProperties: info.additionalProperties }) as TTyped<Partial<ObjectStatic<P>>>;
411
463
  }
412
464
 
413
- function tRequired<P extends Record<string, TSchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
465
+ function tRequired<P extends Record<string, AnySchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
414
466
  const info = requireObject(schema, "Required");
415
- const props: Record<string, TSchema> = {};
467
+ const props: Record<string, AnySchema> = {};
416
468
  for (const key in info.props) {
417
- props[key] = (info.props[key] as unknown as RuntimeType<unknown>)[OPTIONAL_INNER] ?? info.props[key];
469
+ props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ?? info.props[key];
418
470
  }
419
471
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<RequiredProps<P>>;
420
472
  }
421
473
 
422
- function tPick<P extends Record<string, TSchema>, const K extends readonly (keyof P)[]>(
474
+ function tPick<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
423
475
  schema: TObject<P>,
424
476
  keys: K,
425
477
  ): TObject<Pick<P, K[number]>> {
426
478
  const info = requireObject(schema, "Pick");
427
- const props: Record<string, TSchema> = {};
479
+ const props: Record<string, AnySchema> = {};
428
480
  for (const key of keys) if (typeof key === "string" && info.props[key]) props[key] = info.props[key];
429
481
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Pick<P, K[number]>>;
430
482
  }
431
483
 
432
- function tOmit<P extends Record<string, TSchema>, const K extends readonly (keyof P)[]>(
484
+ function tOmit<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
433
485
  schema: TObject<P>,
434
486
  keys: K,
435
487
  ): TObject<Omit<P, K[number]>> {
436
488
  const info = requireObject(schema, "Omit");
437
489
  const omitted = new Set<PropertyKey>(keys);
438
- const props: Record<string, TSchema> = {};
490
+ const props: Record<string, AnySchema> = {};
439
491
  for (const key in info.props) if (!omitted.has(key)) props[key] = info.props[key];
440
492
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Omit<P, K[number]>>;
441
493
  }
442
494
 
443
- function tComposite<const E extends readonly TObject<Record<string, TSchema>>[]>(
495
+ function tComposite<const E extends readonly TObject<Record<string, AnySchema>>[]>(
444
496
  schemas: E,
445
497
  opts?: ObjectOpts,
446
- ): TSchema<UnionToIntersection<Static<E[number]>>> {
447
- const props: Record<string, TSchema> = {};
498
+ ): TTyped<UnionToIntersection<Static<E[number]>>> {
499
+ const props: Record<string, AnySchema> = {};
448
500
  for (const schema of schemas) Object.assign(props, requireObject(schema, "Composite").props);
449
- return tObject(props, opts) as TSchema<UnionToIntersection<Static<E[number]>>>;
501
+ return asSchema<UnionToIntersection<Static<E[number]>>>(tObject(props, opts));
450
502
  }
451
503
 
452
504
  function tUnsafe<T = unknown>(_jsonSchema: Record<string, unknown> = {}): TUnsafe<T> {
@@ -459,10 +511,10 @@ export const Type = {
459
511
  String: tString,
460
512
  Number: (opts?: NumberOpts) => tNumber(opts),
461
513
  Integer: (opts?: NumberOpts) => tNumber(opts, true),
462
- Boolean: (opts?: Meta) => applyMeta(type.raw("boolean") as RuntimeType<boolean>, opts),
463
- Null: (opts?: Meta) => applyMeta(type.raw("null") as RuntimeType<null>, opts),
464
- Any: (opts?: Meta) => applyMeta(type.raw("unknown") as RuntimeType<unknown>, opts),
465
- Unknown: (opts?: Meta) => applyMeta(type.raw("unknown") as RuntimeType<unknown>, opts),
514
+ Boolean: (opts?: Meta) => applyMeta(asRuntime<boolean>(type.raw("boolean")), opts),
515
+ Null: (opts?: Meta) => applyMeta(asRuntime<null>(type.raw("null")), opts),
516
+ Any: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
517
+ Unknown: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
466
518
  Never: tNever,
467
519
  Literal: tLiteral,
468
520
  Union: tUnion,
@@ -474,7 +526,8 @@ export const Type = {
474
526
  Record: tRecord,
475
527
  Optional: tOptional,
476
528
  Nullable: tNullable,
477
- Readonly: <E extends TSchema>(schema: E): E => withLegacyCompat(schema) as unknown as E,
529
+ Readonly: <E extends AnySchema>(schema: E): TReadonly<E> =>
530
+ asSchema<Readonly<Static<E>>>(withLegacyCompat(asRuntime<Readonly<Static<E>>>(schema))),
478
531
  Partial: tPartial,
479
532
  Required: tRequired,
480
533
  Pick: tPick,
package/src/zod.ts CHANGED
@@ -71,7 +71,7 @@ function restrictBase<Out>(source: Decoratable<Out>, ir: IR): Decoratable<Out> {
71
71
  let next = source.hasSteps
72
72
  ? schemaFromIR<Out>({ k: "morph", input: ir, fn: value => source(value) })
73
73
  : schemaFromIR<Out>(ir);
74
- if (source.description !== undefined) next = next.describe(source.description);
74
+ if (source.ir.desc !== undefined) next = next.describe(source.ir.desc);
75
75
  if (source.hasDefault) next = next.default(source.defaultValue as Out | (() => Out));
76
76
  return next;
77
77
  }