@oh-my-pi/omptype 17.2.7 → 17.2.8

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) {
@@ -229,7 +269,7 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
229
269
  const keyword = integer ? "number.integer" : "number";
230
270
  const lowerDsl = lower ? `${lower.value} ${lower.exclusive ? "<" : "<="} ` : "";
231
271
  const upperDsl = upper ? ` ${upper.exclusive ? "<" : "<="} ${upper.value}` : "";
232
- let schema = type.raw(`${lowerDsl}${keyword}${upperDsl}`) as RuntimeType<number>;
272
+ let schema = asRuntime<number>(type.raw(`${lowerDsl}${keyword}${upperDsl}`));
233
273
  if (opts?.multipleOf !== undefined) {
234
274
  const divisor = opts.multipleOf;
235
275
  schema = schema.narrow((value, ctx) => {
@@ -244,33 +284,32 @@ function tNumber(opts?: NumberOpts, integer = false): TNumber {
244
284
  }
245
285
 
246
286
  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);
287
+ return applyMeta(asRuntime<V>(type.enumerated(value)), opts);
248
288
  }
249
289
 
250
290
  function tNever(opts?: Meta): TNever {
251
291
  return applyMeta(
252
- (type.raw("unknown") as RuntimeType<unknown>).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
292
+ asRuntime<unknown>(type.raw("unknown")).narrow((_value, ctx): _value is never => ctx.mustBe("never")),
253
293
  opts,
254
294
  );
255
295
  }
256
296
 
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>;
297
+ function tUnion<const E extends readonly AnySchema[]>(schemas: E, opts?: Meta): TUnion<E> {
298
+ if (schemas.length === 0) return asSchema<Static<E[number]>>(tNever(opts));
299
+ let result = asRuntime<unknown>(schemas[0]);
260
300
  for (let i = 1; i < schemas.length; i++) result = result.or(schemas[i]);
261
- return applyMeta(result, opts) as TUnion<E>;
301
+ return asSchema<Static<E[number]>>(applyMeta(result, opts));
262
302
  }
263
303
 
264
- function tIntersect<const E extends readonly TSchema[]>(
304
+ function tIntersect<const E extends readonly AnySchema[]>(
265
305
  schemas: E,
266
306
  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
- >;
307
+ ): TTyped<UnionToIntersection<Static<E[number]>>> {
308
+ if (schemas.length === 0) {
309
+ return applyMeta(asRuntime<UnionToIntersection<Static<E[number]>>>(type.raw("unknown")), opts);
310
+ }
272
311
  const validateAll = (): RuntimeType<UnionToIntersection<Static<E[number]>>> => {
273
- const base = type.raw("unknown") as RuntimeType<unknown>;
312
+ const base = asRuntime<unknown>(type.raw("unknown"));
274
313
  return base.narrow((value, ctx): value is UnionToIntersection<Static<E[number]>> => {
275
314
  for (const schema of schemas) {
276
315
  if (schema(value) instanceof type.errors) return ctx.mustBe("a value satisfying every intersection member");
@@ -279,14 +318,14 @@ function tIntersect<const E extends readonly TSchema[]>(
279
318
  });
280
319
  };
281
320
  if (schemas.some(schema => schema.hasSteps)) return applyMeta(validateAll(), opts);
282
- let result = schemas[0] as unknown as RuntimeType<unknown>;
321
+ let result = asRuntime<unknown>(schemas[0]);
283
322
  try {
284
323
  for (let i = 1; i < schemas.length; i++) result = result.and(schemas[i]);
285
324
  } catch (error) {
286
325
  if (error instanceof OmpTypeError) return applyMeta(validateAll(), opts);
287
326
  throw error;
288
327
  }
289
- return applyMeta(result, opts) as TSchema<UnionToIntersection<Static<E[number]>>>;
328
+ return asSchema<UnionToIntersection<Static<E[number]>>>(applyMeta(result, opts));
290
329
  }
291
330
  type UnionToIntersection<U> = (U extends unknown ? (value: U) => void : never) extends (value: infer I) => void
292
331
  ? I
@@ -306,16 +345,17 @@ function enumValues(values: Record<string, string | number> | readonly (string |
306
345
  function tEnum<const E extends Record<string, string | number> | readonly (string | number)[]>(
307
346
  values: E,
308
347
  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
- >;
348
+ ): TTyped<E extends readonly (infer V)[] ? V : E[keyof E]> {
349
+ return applyMeta(
350
+ asRuntime<E extends readonly (infer V)[] ? V : E[keyof E]>(type.enumerated(...enumValues(values))),
351
+ opts,
352
+ );
313
353
  }
314
354
 
315
- function tArray<E extends TSchema>(item: E, opts?: ArrayOpts): TArray<E> {
355
+ function tArray<E extends AnySchema>(item: E, opts?: ArrayOpts): TArray<E> {
316
356
  checkFiniteOption("minItems", opts?.minItems);
317
357
  checkFiniteOption("maxItems", opts?.maxItems);
318
- let schema = (item as unknown as RuntimeType<Static<E>>).array();
358
+ let schema = asRuntime<Static<E>>(item).array();
319
359
  if (opts?.minItems !== undefined) schema = schema.atLeastLength(opts.minItems);
320
360
  if (opts?.maxItems !== undefined) schema = schema.atMostLength(opts.maxItems);
321
361
  if (opts?.uniqueItems) {
@@ -342,8 +382,8 @@ function jsonEqual(left: unknown, right: unknown): boolean {
342
382
  }
343
383
  }
344
384
 
345
- function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTuple<E> {
346
- const schema = (type.raw("unknown") as RuntimeType<unknown>).narrow(
385
+ function tTuple<const E extends readonly AnySchema[]>(items: E, opts?: Meta): TTuple<E> {
386
+ const schema = asRuntime<unknown>(type.raw("unknown")).narrow(
347
387
  (value, ctx): value is { -readonly [K in keyof E]: Static<E[K]> } => {
348
388
  if (!Array.isArray(value) || value.length !== items.length)
349
389
  return ctx.mustBe(`a tuple of length ${items.length}`);
@@ -355,25 +395,29 @@ function tTuple<const E extends readonly TSchema[]>(items: E, opts?: Meta): TTup
355
395
  return applyMeta(schema, opts);
356
396
  }
357
397
 
358
- function tObject<const P extends Record<string, TSchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
398
+ function tObject<const P extends Record<string, AnySchema>>(properties: P, opts?: ObjectOpts): TObject<P> {
359
399
  const def: Record<string, Def> = {};
360
- const props: Record<string, TSchema> = {};
400
+ const props: Record<string, AnySchema> = {};
361
401
  for (const key in properties) {
362
402
  const schema = properties[key];
363
- const inner = (schema as unknown as RuntimeType<unknown>)[OPTIONAL_INNER];
364
- def[inner ? `${key}?` : key] = (inner ?? schema) as Def;
403
+ const inner = asRuntime<unknown>(schema)[OPTIONAL_INNER];
404
+ // A defaulted `Type.Optional(...)` maps to a plain defaulted key:
405
+ // omptype (like ArkType) rejects `key?` with a default, and a default
406
+ // already makes the key omittable on input.
407
+ const optionalKey = inner !== undefined && !asRuntime<unknown>(inner).hasDefault;
408
+ def[optionalKey ? `${key}?` : key] = inner ?? schema;
365
409
  props[key] = schema;
366
410
  }
367
411
  if (opts?.additionalProperties === false) def["+"] = "reject";
368
412
  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);
413
+ def["[string]"] = opts.additionalProperties;
414
+ const schema = applyMeta(asRuntime<ObjectStatic<P>>(type.raw(def)), opts);
371
415
  schema[OBJECT_INFO] = { props, additionalProperties: opts?.additionalProperties };
372
416
  return schema;
373
417
  }
374
418
 
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) => {
419
+ function tRecord<K extends AnySchema, V extends AnySchema>(key: K, value: V, opts?: Meta): TRecord<K, V> {
420
+ const base = asRuntime<Record<string, Static<V>>>(type.raw({ "[string]": value })).narrow((record, ctx) => {
377
421
  for (const name in record)
378
422
  if (key(name) instanceof type.errors) return ctx.mustBe("an object with valid record keys");
379
423
  return true;
@@ -381,72 +425,70 @@ function tRecord<K extends TSchema, V extends TSchema>(key: K, value: V, opts?:
381
425
  return applyMeta(base, opts) as TRecord<K, V>;
382
426
  }
383
427
 
384
- function tOptional<E extends TSchema>(schema: E, opts?: Meta): TOptional<E> {
428
+ function tOptional<E extends AnySchema>(schema: E, opts?: Meta): TOptional<E> {
385
429
  const marker = applyMeta(
386
- (schema as unknown as RuntimeType<Static<E>>).or(type.raw("undefined")),
430
+ asRuntime<Static<E>>(schema).or(asRuntime<undefined>(type.raw("undefined"))),
387
431
  opts,
388
432
  ) as RuntimeType<Static<E> | undefined>;
389
433
  marker[OPTIONAL_INNER] = schema;
390
434
  return marker as unknown as TOptional<E>;
391
435
  }
392
436
 
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);
437
+ function tNullable<E extends AnySchema>(schema: E, opts?: Meta): TTyped<Static<E> | null> {
438
+ return applyMeta(asRuntime<Static<E>>(schema).or(asRuntime<null>(type.raw("null"))), opts);
395
439
  }
396
440
 
397
- function requireObject(schema: TSchema, operation: string): ObjectInfo {
398
- const info = (schema as unknown as RuntimeType<unknown>)[OBJECT_INFO];
441
+ function requireObject(schema: AnySchema, operation: string): ObjectInfo {
442
+ const info = asRuntime<unknown>(schema)[OBJECT_INFO];
399
443
  if (!info) throw new OmpTypeError(`Type.${operation} requires a schema created by Type.Object`);
400
444
  return info;
401
445
  }
402
446
 
403
- function tPartial<P extends Record<string, TSchema>>(schema: TObject<P>): TSchema<Partial<ObjectStatic<P>>> {
447
+ function tPartial<P extends Record<string, AnySchema>>(schema: TObject<P>): TTyped<Partial<ObjectStatic<P>>> {
404
448
  const info = requireObject(schema, "Partial");
405
- const props: Record<string, TSchema> = {};
449
+ const props: Record<string, AnySchema> = {};
406
450
  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>>>;
451
+ props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ? info.props[key] : tOptional(info.props[key]);
452
+ return tObject(props, { additionalProperties: info.additionalProperties }) as TTyped<Partial<ObjectStatic<P>>>;
411
453
  }
412
454
 
413
- function tRequired<P extends Record<string, TSchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
455
+ function tRequired<P extends Record<string, AnySchema>>(schema: TObject<P>): TObject<RequiredProps<P>> {
414
456
  const info = requireObject(schema, "Required");
415
- const props: Record<string, TSchema> = {};
457
+ const props: Record<string, AnySchema> = {};
416
458
  for (const key in info.props) {
417
- props[key] = (info.props[key] as unknown as RuntimeType<unknown>)[OPTIONAL_INNER] ?? info.props[key];
459
+ props[key] = asRuntime<unknown>(info.props[key])[OPTIONAL_INNER] ?? info.props[key];
418
460
  }
419
461
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<RequiredProps<P>>;
420
462
  }
421
463
 
422
- function tPick<P extends Record<string, TSchema>, const K extends readonly (keyof P)[]>(
464
+ function tPick<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
423
465
  schema: TObject<P>,
424
466
  keys: K,
425
467
  ): TObject<Pick<P, K[number]>> {
426
468
  const info = requireObject(schema, "Pick");
427
- const props: Record<string, TSchema> = {};
469
+ const props: Record<string, AnySchema> = {};
428
470
  for (const key of keys) if (typeof key === "string" && info.props[key]) props[key] = info.props[key];
429
471
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Pick<P, K[number]>>;
430
472
  }
431
473
 
432
- function tOmit<P extends Record<string, TSchema>, const K extends readonly (keyof P)[]>(
474
+ function tOmit<P extends Record<string, AnySchema>, const K extends readonly (keyof P)[]>(
433
475
  schema: TObject<P>,
434
476
  keys: K,
435
477
  ): TObject<Omit<P, K[number]>> {
436
478
  const info = requireObject(schema, "Omit");
437
479
  const omitted = new Set<PropertyKey>(keys);
438
- const props: Record<string, TSchema> = {};
480
+ const props: Record<string, AnySchema> = {};
439
481
  for (const key in info.props) if (!omitted.has(key)) props[key] = info.props[key];
440
482
  return tObject(props, { additionalProperties: info.additionalProperties }) as TObject<Omit<P, K[number]>>;
441
483
  }
442
484
 
443
- function tComposite<const E extends readonly TObject<Record<string, TSchema>>[]>(
485
+ function tComposite<const E extends readonly TObject<Record<string, AnySchema>>[]>(
444
486
  schemas: E,
445
487
  opts?: ObjectOpts,
446
- ): TSchema<UnionToIntersection<Static<E[number]>>> {
447
- const props: Record<string, TSchema> = {};
488
+ ): TTyped<UnionToIntersection<Static<E[number]>>> {
489
+ const props: Record<string, AnySchema> = {};
448
490
  for (const schema of schemas) Object.assign(props, requireObject(schema, "Composite").props);
449
- return tObject(props, opts) as TSchema<UnionToIntersection<Static<E[number]>>>;
491
+ return asSchema<UnionToIntersection<Static<E[number]>>>(tObject(props, opts));
450
492
  }
451
493
 
452
494
  function tUnsafe<T = unknown>(_jsonSchema: Record<string, unknown> = {}): TUnsafe<T> {
@@ -459,10 +501,10 @@ export const Type = {
459
501
  String: tString,
460
502
  Number: (opts?: NumberOpts) => tNumber(opts),
461
503
  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),
504
+ Boolean: (opts?: Meta) => applyMeta(asRuntime<boolean>(type.raw("boolean")), opts),
505
+ Null: (opts?: Meta) => applyMeta(asRuntime<null>(type.raw("null")), opts),
506
+ Any: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
507
+ Unknown: (opts?: Meta) => applyMeta(asRuntime<unknown>(type.raw("unknown")), opts),
466
508
  Never: tNever,
467
509
  Literal: tLiteral,
468
510
  Union: tUnion,
@@ -474,7 +516,8 @@ export const Type = {
474
516
  Record: tRecord,
475
517
  Optional: tOptional,
476
518
  Nullable: tNullable,
477
- Readonly: <E extends TSchema>(schema: E): E => withLegacyCompat(schema) as unknown as E,
519
+ Readonly: <E extends AnySchema>(schema: E): TReadonly<E> =>
520
+ asSchema<Readonly<Static<E>>>(withLegacyCompat(asRuntime<Readonly<Static<E>>>(schema))),
478
521
  Partial: tPartial,
479
522
  Required: tRequired,
480
523
  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
  }