ts-fortress 12.0.2 → 12.0.4

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.
@@ -1 +1 @@
1
- {"version":3,"file":"intersection.d.mts","sourceRoot":"","sources":["../../src/compose/intersection.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAEL,KAAK,OAAO,EAEZ,KAAK,IAAI,EACT,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AASrB,eAAO,MAAM,YAAY,GAAI,KAAK,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,SAC9D,KAAK,eACC,gBAAgB,CAAC,KAAK,CAAC,YAC1B,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,gBAAgB,CAAC,KAAK,CAmFxB,CAAC;AAmCF,KAAK,gBAAgB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI,CAChE,qBAAqB,CAAC,KAAK,CAAC,CAC7B,CAAC;AAEF,KAAK,qBAAqB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAC7D,kBAAkB,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;AAEtD,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,yBAAyB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACxE,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7C,KAAK,KAAK,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAClE,CAAC,GACD,KAAK,CAAC;;CACX;AA4BD,KAAK,cAAc,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,IAClD,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAE3C,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,cAAc,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,IACzD,KAAK,SAAS,SAAS,EAAE,GACrB,SAAS,EAAE,GACX,KAAK,SAAS,SAAS,CAAC,MAAM,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,GAChD,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,GACvD,KAAK,CAAC;IAEd,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;;CACnD"}
1
+ {"version":3,"file":"intersection.d.mts","sourceRoot":"","sources":["../../src/compose/intersection.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAEL,KAAK,OAAO,EAEZ,KAAK,IAAI,EACT,KAAK,MAAM,EACZ,MAAM,aAAa,CAAC;AASrB,eAAO,MAAM,YAAY,GAAI,KAAK,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,SAC9D,KAAK,eACC,gBAAgB,CAAC,KAAK,CAAC,YAC1B,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,gBAAgB,CAAC,KAAK,CAmFxB,CAAC;AA+BF,KAAK,gBAAgB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAAI,IAAI,CAChE,qBAAqB,CAAC,KAAK,CAAC,CAC7B,CAAC;AAEF,KAAK,qBAAqB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IAC7D,kBAAkB,CAAC,yBAAyB,CAAC,KAAK,CAAC,CAAC;AAEtD,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,yBAAyB,CAAC,KAAK,SAAS,aAAa,CAAC,OAAO,CAAC,IACxE,YAAY,CAAC,KAAK,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAE7C,KAAK,KAAK,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,SAAS,SAAS,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,GAClE,CAAC,GACD,KAAK,CAAC;;CACX;AA4BD,KAAK,cAAc,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,IAClD,kBAAkB,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;AAE3C,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,cAAc,CAAC,KAAK,SAAS,SAAS,OAAO,EAAE,IACzD,KAAK,SAAS,SAAS,EAAE,GACrB,SAAS,EAAE,GACX,KAAK,SAAS,SAAS,CAAC,MAAM,IAAI,EAAE,GAAG,MAAM,IAAI,CAAC,GAChD,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC,GACvD,KAAK,CAAC;IAEd,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;;CACnD"}
@@ -1,4 +1,4 @@
1
- import { Arr, Result, isRecord, tp, hasKey } from 'ts-data-forge';
1
+ import { Arr, Result, isRecord, Obj, hasKey } from 'ts-data-forge';
2
2
  import { hasRecordInternals } from '../type.mjs';
3
3
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
4
4
  import { createCastFn } from '../utils/create-cast-fn.mjs';
@@ -70,14 +70,11 @@ const intersection = (types, defaultType, options) => {
70
70
  };
71
71
  const mergePruned = (x, y) => {
72
72
  if (isRecord(x) && isRecord(y)) {
73
- const xMergedWithY = Object.fromEntries(
74
- Object.entries(x).map(
75
- ([k, xv]) => tp(k, hasKey(y, k) ? mergePruned(xv, y[k]) : xv)
76
- )
77
- );
78
- const yOnly = Object.fromEntries(
79
- Object.entries(y).filter(([k]) => !hasKey(x, k))
73
+ const xMergedWithY = Obj.map(
74
+ x,
75
+ (xv, k) => hasKey(y, k) ? mergePruned(xv, y[k]) : xv
80
76
  );
77
+ const yOnly = Obj.filter(y, (_yv, k) => !hasKey(x, k));
81
78
  return { ...xMergedWithY, ...yOnly };
82
79
  }
83
80
  if (Arr.isArray(x) && Arr.isArray(y) && x.length === y.length) {
@@ -1 +1 @@
1
- {"version":3,"file":"intersection.mjs","sources":["../../src/compose/intersection.mts"],"sourcesContent":["import { Arr, expectType, hasKey, isRecord, Result, tp } from 'ts-data-forge';\nimport { type Intersection, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n toIntersectionString,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const intersection = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n defaultType: IntersectionType<Types>,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): IntersectionType<Types> => {\n type T = IntersectionTypeValue<Types>;\n\n const typeNameFilled: string =\n options?.typeName ??\n `(${toIntersectionString(types.map((a) => a.typeName))})`;\n\n const validate: Type<T>['validate'] = (a) => {\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const type of types) {\n const res = type.validate(a);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'intersection',\n typeNames: types.map((t) => t.typeName),\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : defaultType.fill(a));\n\n const baseType: Type<T> = {\n typeName: typeNameFilled,\n defaultValue: defaultType.defaultValue,\n fill,\n // Non-record intersections (e.g. branded primitives) have no excess paths\n // to remove. Record intersections override this below.\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n } as const;\n\n // If all types are records, add RecordTypeInternals\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n // A value path is represented by a record intersection if it is\n // represented by any member, so the pruned members are merged (deeply;\n // see `mergePruned`). All members are record types here\n // (`hasRecordInternals`), so each pruned result is a record.\n prune: (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion, @typescript-eslint/no-unsafe-return\n types.map((t) => t.prune(a)).reduce(mergePruned, {}) as T,\n shapeStructure: Arr.isFixedLengthTuple(1, shapeStructures)\n ? shapeStructures[0]\n : ({ kind: 'intersection', parts: shapeStructures } as const),\n excessProperty,\n } as IntersectionType<Types>;\n }\n\n return baseType;\n};\n\n/**\n * Deep-merges the pruned results of intersection members. Each pruned result\n * contains only the value paths represented by its own member type, so the\n * results have to be merged recursively to keep the union of all represented\n * paths — a shallow spread would drop nested paths kept by an earlier member\n * whenever a later member shares the same key (e.g. two members both having a\n * `pos` sub-record with different fields).\n */\nconst mergePruned = (x: unknown, y: unknown): unknown => {\n if (isRecord(x) && isRecord(y)) {\n const xMergedWithY = Object.fromEntries(\n Object.entries(x).map(([k, xv]) =>\n tp(k, hasKey(y, k) ? mergePruned(xv, y[k]) : xv),\n ),\n );\n\n const yOnly = Object.fromEntries(\n Object.entries(y).filter(([k]) => !hasKey(x, k)),\n );\n\n return { ...xMergedWithY, ...yOnly };\n }\n\n // Both members pruned the same input array, so the lengths always match;\n // merge element-wise to keep every represented element path.\n if (Arr.isArray(x) && Arr.isArray(y) && x.length === y.length) {\n return x.map((xi, i) => mergePruned(xi, y[i]));\n }\n\n // Not structurally mergeable — the later member wins.\n return y;\n};\n\ntype IntersectionType<Types extends NonEmptyTuple<AnyType>> = Type<\n IntersectionTypeValue<Types>\n>;\n\ntype IntersectionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.IntersectionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type IntersectionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n Intersection<Cast0<UnwrapTypeList<Types>>>;\n\n type Cast0<T> = readonly [T] extends readonly [NonEmptyTuple<unknown>]\n ? T\n : never;\n}\n\nexpectType<\n IntersectionType<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n Type<\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n >\n>('=');\n\ntype UnwrapTypeList<Types extends readonly AnyType[]> =\n TsFortressInternal.UnwrapTypeImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnwrapTypeImpl<Types extends readonly unknown[]> =\n Types extends readonly []\n ? readonly []\n : Types extends readonly [infer Head, ...infer Tail]\n ? readonly [TypeOf<Cast1<Head>>, ...UnwrapTypeImpl<Tail>]\n : never;\n\n type Cast1<T> = [T] extends [AnyType] ? T : never;\n}\n\nexpectType<\n TypeOf<\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >\n >,\n Readonly<{\n a: 0;\n b: 0;\n }>\n>('=');\n\nexpectType<\n UnwrapTypeList<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n Readonly<{\n c: 0;\n d: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n d: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 1;\n c: 0;\n }>,\n ]\n >,\n never\n>('=');\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"intersection.mjs","sources":["../../src/compose/intersection.mts"],"sourcesContent":["import { Arr, expectType, hasKey, isRecord, Obj, Result } from 'ts-data-forge';\nimport { type Intersection, type NonEmptyTuple } from 'ts-type-forge';\nimport {\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n toIntersectionString,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const intersection = <const Types extends NonEmptyTuple<AnyType>>(\n types: Types,\n defaultType: IntersectionType<Types>,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): IntersectionType<Types> => {\n type T = IntersectionTypeValue<Types>;\n\n const typeNameFilled: string =\n options?.typeName ??\n `(${toIntersectionString(types.map((a) => a.typeName))})`;\n\n const validate: Type<T>['validate'] = (a) => {\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const type of types) {\n const res = type.validate(a);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: a,\n expectedType: typeNameFilled,\n typeName: typeNameFilled,\n details: {\n kind: 'intersection',\n typeNames: types.map((t) => t.typeName),\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const is = createIsFn<T>(validate);\n\n const fill: Type<T>['fill'] = (a) => (is(a) ? a : defaultType.fill(a));\n\n const baseType: Type<T> = {\n typeName: typeNameFilled,\n defaultValue: defaultType.defaultValue,\n fill,\n // Non-record intersections (e.g. branded primitives) have no excess paths\n // to remove. Record intersections override this below.\n prune: (a) => a,\n validate,\n is,\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n } as const;\n\n // If all types are records, add RecordTypeInternals\n if (types.every(hasRecordInternals)) {\n const shapeStructures = Arr.map(types, (t) => t.shapeStructure);\n\n const excessProperty: ExcessPropertyOption = Arr.some(\n types,\n (t) => t.excessProperty === 'reject',\n )\n ? 'reject'\n : 'allow';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n ...baseType,\n // A value path is represented by a record intersection if it is\n // represented by any member, so the pruned members are merged (deeply;\n // see `mergePruned`). All members are record types here\n // (`hasRecordInternals`), so each pruned result is a record.\n prune: (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion, @typescript-eslint/no-unsafe-return\n types.map((t) => t.prune(a)).reduce(mergePruned, {}) as T,\n shapeStructure: Arr.isFixedLengthTuple(1, shapeStructures)\n ? shapeStructures[0]\n : ({ kind: 'intersection', parts: shapeStructures } as const),\n excessProperty,\n } as IntersectionType<Types>;\n }\n\n return baseType;\n};\n\n/**\n * Deep-merges the pruned results of intersection members. Each pruned result\n * contains only the value paths represented by its own member type, so the\n * results have to be merged recursively to keep the union of all represented\n * paths — a shallow spread would drop nested paths kept by an earlier member\n * whenever a later member shares the same key (e.g. two members both having a\n * `pos` sub-record with different fields).\n */\nconst mergePruned = (x: unknown, y: unknown): unknown => {\n if (isRecord(x) && isRecord(y)) {\n const xMergedWithY = Obj.map(x, (xv, k) =>\n hasKey(y, k) ? mergePruned(xv, y[k]) : xv,\n );\n\n const yOnly = Obj.filter(y, (_yv, k) => !hasKey(x, k));\n\n return { ...xMergedWithY, ...yOnly };\n }\n\n // Both members pruned the same input array, so the lengths always match;\n // merge element-wise to keep every represented element path.\n if (Arr.isArray(x) && Arr.isArray(y) && x.length === y.length) {\n return x.map((xi, i) => mergePruned(xi, y[i]));\n }\n\n // Not structurally mergeable — the later member wins.\n return y;\n};\n\ntype IntersectionType<Types extends NonEmptyTuple<AnyType>> = Type<\n IntersectionTypeValue<Types>\n>;\n\ntype IntersectionTypeValue<Types extends NonEmptyTuple<AnyType>> =\n TsFortressInternal.IntersectionTypeValueImpl<Types>;\n\nnamespace TsFortressInternal {\n export type IntersectionTypeValueImpl<Types extends NonEmptyTuple<AnyType>> =\n Intersection<Cast0<UnwrapTypeList<Types>>>;\n\n type Cast0<T> = readonly [T] extends readonly [NonEmptyTuple<unknown>]\n ? T\n : never;\n}\n\nexpectType<\n IntersectionType<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n Type<\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n >\n>('=');\n\ntype UnwrapTypeList<Types extends readonly AnyType[]> =\n TsFortressInternal.UnwrapTypeImpl<Types>;\n\nnamespace TsFortressInternal {\n export type UnwrapTypeImpl<Types extends readonly unknown[]> =\n Types extends readonly []\n ? readonly []\n : Types extends readonly [infer Head, ...infer Tail]\n ? readonly [TypeOf<Cast1<Head>>, ...UnwrapTypeImpl<Tail>]\n : never;\n\n type Cast1<T> = [T] extends [AnyType] ? T : never;\n}\n\nexpectType<\n TypeOf<\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >\n >,\n Readonly<{\n a: 0;\n b: 0;\n }>\n>('=');\n\nexpectType<\n UnwrapTypeList<\n readonly [\n Type<\n Readonly<{\n a: 0;\n b: 0;\n }>\n >,\n Type<\n Readonly<{\n b: 0;\n c: 0;\n }>\n >,\n ]\n >,\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 0;\n c: 0;\n }>,\n Readonly<{\n c: 0;\n d: 0;\n }>,\n ]\n >,\n Readonly<{\n a: 0;\n b: 0;\n c: 0;\n d: 0;\n }>\n>('=');\n\nexpectType<\n Intersection<\n readonly [\n Readonly<{\n a: 0;\n b: 0;\n }>,\n Readonly<{\n b: 1;\n c: 0;\n }>,\n ]\n >,\n never\n>('=');\n"],"names":[],"mappings":"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"}
@@ -71,35 +71,35 @@ const createConstraintsPredicate = (constraints) => (value) => {
71
71
  return Result.err({ constraint: "nonPositive", value: true });
72
72
  }
73
73
  if (gt !== void 0 && !(value > gt)) {
74
- return Result.err({ constraint: "gt", value: String(gt) });
74
+ return Result.err({ constraint: "gt", value: gt.toString() });
75
75
  }
76
76
  if (gte !== void 0 && !(value >= gte)) {
77
- return Result.err({ constraint: "gte", value: String(gte) });
77
+ return Result.err({ constraint: "gte", value: gte.toString() });
78
78
  }
79
79
  if (min !== void 0 && !(value >= min)) {
80
- return Result.err({ constraint: "min", value: String(min) });
80
+ return Result.err({ constraint: "min", value: min.toString() });
81
81
  }
82
82
  if (lt !== void 0 && !(value < lt)) {
83
- return Result.err({ constraint: "lt", value: String(lt) });
83
+ return Result.err({ constraint: "lt", value: lt.toString() });
84
84
  }
85
85
  if (lte !== void 0 && !(value <= lte)) {
86
- return Result.err({ constraint: "lte", value: String(lte) });
86
+ return Result.err({ constraint: "lte", value: lte.toString() });
87
87
  }
88
88
  if (max !== void 0 && !(value <= max)) {
89
- return Result.err({ constraint: "max", value: String(max) });
89
+ return Result.err({ constraint: "max", value: max.toString() });
90
90
  }
91
91
  if (multipleOf !== void 0) {
92
92
  if (multipleOf === 0n) {
93
93
  if (value !== 0n) {
94
94
  return Result.err({
95
95
  constraint: "multipleOf",
96
- value: String(multipleOf)
96
+ value: multipleOf.toString()
97
97
  });
98
98
  }
99
99
  } else if (value % multipleOf !== 0n) {
100
100
  return Result.err({
101
101
  constraint: "multipleOf",
102
- value: String(multipleOf)
102
+ value: multipleOf.toString()
103
103
  });
104
104
  }
105
105
  }
@@ -108,11 +108,14 @@ const createConstraintsPredicate = (constraints) => (value) => {
108
108
  if (value !== 0n) {
109
109
  return Result.err({
110
110
  constraint: "step",
111
- value: String(step)
111
+ value: step.toString()
112
112
  });
113
113
  }
114
114
  } else if (value % step !== 0n) {
115
- return Result.err({ constraint: "step", value: String(step) });
115
+ return Result.err({
116
+ constraint: "step",
117
+ value: step.toString()
118
+ });
116
119
  }
117
120
  }
118
121
  return Result.ok(true);
@@ -1 +1 @@
1
- {"version":3,"file":"bigint.mjs","sources":["../../src/primitives/bigint.mts"],"sourcesContent":["/* eslint-disable unicorn/no-negated-comparison */\nimport { Arr, expectType, isBigint, Result } from 'ts-data-forge';\nimport { type BoolAnd, type BoolNot } from 'ts-type-forge';\nimport { refine } from '../other-types/index.mjs';\nimport { type Type } from '../type.mjs';\nimport {\n createPrimitiveType,\n type NumericConstraintViolation,\n} from '../utils/index.mjs';\n\ntype NumberType = bigint;\n\nexport function bigint(defaultValue?: NumberType): Type<NumberType>;\n\nexport function bigint<N extends NumberType, const C extends Constraints>(\n defaultValue: N & DefaultValueType<N, C>,\n constraints: C,\n): Type<NumberType>;\n\nexport function bigint<C extends Constraints>(\n defaultValue: NumberType = 0n,\n constraints?: C,\n): Type<NumberType> {\n const baseType = createPrimitiveType({\n typeName: 'bigint',\n defaultValue,\n is: isBigint,\n });\n\n if (constraints === undefined || Arr.isEmpty(Object.keys(constraints))) {\n return baseType;\n }\n\n const constraintsPredicate = createConstraintsPredicate(constraints);\n\n const defaultValueConstraintsCheck = constraintsPredicate(defaultValue);\n\n if (Result.isErr(defaultValueConstraintsCheck)) {\n throw new Error(\n defaultValueErrorMessage(\n defaultValue,\n defaultValueConstraintsCheck.value,\n ),\n );\n }\n\n return refine({\n baseType,\n defaultValue,\n is: (value): value is NumberType =>\n Result.isOk(constraintsPredicate(value)),\n typeName: 'bigint',\n getConstraintDetails: (value) => {\n const result = constraintsPredicate(value);\n\n return Result.isErr(result)\n ? {\n kind: 'numeric-constraint',\n numericType: 'bigint',\n violation: result.value,\n }\n : undefined;\n },\n });\n}\n\ntype Constraints = Partial<\n Readonly<{\n nonZero: true;\n negative: true;\n nonNegative: true;\n positive: true;\n nonPositive: true;\n\n gt: NumberType;\n gte: NumberType;\n min: NumberType;\n lt: NumberType;\n lte: NumberType;\n max: NumberType;\n multipleOf: NumberType;\n step: NumberType;\n }>\n>;\n\ntype DefaultValueType<\n N extends NumberType,\n C extends Constraints,\n> = DefaultValueWhenNonZeroIsOn<N, C> &\n DefaultValueWhenNegativeIsOn<N, C> &\n DefaultValueWhenNonNegativeIsOn<N, C> &\n DefaultValueWhenPositiveIsOn<N, C> &\n DefaultValueWhenNonPositiveIsOn<N, C>;\n\ntype DefaultValueWhenNonZeroIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ nonZero: true }> ? NonZeroNumber<N> : NumberType;\n\ntype DefaultValueWhenNegativeIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ negative: true }> ? NegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenNonNegativeIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonNegative: true }> ? NonNegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenPositiveIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ positive: true }> ? PositiveNumber<N> : NumberType;\n\ntype DefaultValueWhenNonPositiveIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonPositive: true }> ? NonPositiveNumber<N> : NumberType;\n\ntype NonZeroNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsZero<N> extends true\n ? never\n : N;\n\ntype NegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNegative<N> extends true\n ? N\n : never;\n\ntype NonNegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonNegative<N> extends true\n ? N\n : never;\n\ntype PositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsPositive<N> extends true\n ? N\n : never;\n\ntype NonPositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonPositive<N> extends true\n ? N\n : never;\n\ntype IsZero<N extends NumberType> = `${N}` extends '0' ? true : false;\n\ntype IsNonZero<N extends NumberType> = IsZero<N> extends true ? false : true;\n\ntype IsNegative<N extends NumberType> = `${N}` extends `-${string}`\n ? true\n : false;\n\ntype IsNonNegative<N extends NumberType> =\n IsNegative<N> extends true ? false : true;\n\ntype IsPositive<N extends NumberType> = BoolAnd<IsNonZero<N>, IsNonNegative<N>>;\n\ntype IsNonPositive<N extends NumberType> = BoolNot<IsPositive<N>>;\n\nconst createConstraintsPredicate =\n (constraints: Constraints) =>\n (value: NumberType): Result<true, NumericConstraintViolation> => {\n const {\n nonZero,\n negative,\n nonNegative,\n positive,\n nonPositive,\n gt,\n gte,\n min,\n lt,\n lte,\n max,\n multipleOf,\n step,\n ..._rest\n } = constraints;\n\n expectType<keyof typeof _rest, never>('=');\n\n if (nonZero === true && !(value !== 0n)) {\n return Result.err({ constraint: 'nonZero', value: true } as const);\n }\n\n if (negative === true && !(value < 0n)) {\n return Result.err({ constraint: 'negative', value: true } as const);\n }\n\n if (nonNegative === true && !(value >= 0n)) {\n return Result.err({ constraint: 'nonNegative', value: true } as const);\n }\n\n if (positive === true && !(value > 0n)) {\n return Result.err({ constraint: 'positive', value: true } as const);\n }\n\n if (nonPositive === true && !(value <= 0n)) {\n return Result.err({ constraint: 'nonPositive', value: true } as const);\n }\n\n if (gt !== undefined && !(value > gt)) {\n return Result.err({ constraint: 'gt', value: String(gt) } as const);\n }\n\n if (gte !== undefined && !(value >= gte)) {\n return Result.err({ constraint: 'gte', value: String(gte) } as const);\n }\n\n if (min !== undefined && !(value >= min)) {\n return Result.err({ constraint: 'min', value: String(min) } as const);\n }\n\n if (lt !== undefined && !(value < lt)) {\n return Result.err({ constraint: 'lt', value: String(lt) } as const);\n }\n\n if (lte !== undefined && !(value <= lte)) {\n return Result.err({ constraint: 'lte', value: String(lte) } as const);\n }\n\n if (max !== undefined && !(value <= max)) {\n return Result.err({ constraint: 'max', value: String(max) } as const);\n }\n\n // `value % 0n` throws a RangeError, so the zero divisor is handled\n // separately: it only admits zero.\n if (multipleOf !== undefined) {\n if (multipleOf === 0n) {\n if (value !== 0n) {\n return Result.err({\n constraint: 'multipleOf',\n value: String(multipleOf),\n } as const);\n }\n } else if (value % multipleOf !== 0n) {\n return Result.err({\n constraint: 'multipleOf',\n value: String(multipleOf),\n } as const);\n }\n }\n\n if (step !== undefined) {\n if (step === 0n) {\n if (value !== 0n) {\n return Result.err({\n constraint: 'step',\n value: String(step),\n } as const);\n }\n } else if (value % step !== 0n) {\n return Result.err({ constraint: 'step', value: String(step) } as const);\n }\n }\n\n return Result.ok(true);\n };\n\nconst defaultValueErrorMessage = (\n value: NumberType,\n violation: NumericConstraintViolation,\n): string =>\n `defaultValue [${value}] for bigint does not satisfy the constraint ${violation.constraint} = ${violation.value}` as const;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bigint.mjs","sources":["../../src/primitives/bigint.mts"],"sourcesContent":["/* eslint-disable unicorn/no-negated-comparison */\nimport { Arr, expectType, isBigint, Result } from 'ts-data-forge';\nimport { type BoolAnd, type BoolNot } from 'ts-type-forge';\nimport { refine } from '../other-types/index.mjs';\nimport { type Type } from '../type.mjs';\nimport {\n createPrimitiveType,\n type NumericConstraintViolation,\n} from '../utils/index.mjs';\n\ntype NumberType = bigint;\n\nexport function bigint(defaultValue?: NumberType): Type<NumberType>;\n\nexport function bigint<N extends NumberType, const C extends Constraints>(\n defaultValue: N & DefaultValueType<N, C>,\n constraints: C,\n): Type<NumberType>;\n\nexport function bigint<C extends Constraints>(\n defaultValue: NumberType = 0n,\n constraints?: C,\n): Type<NumberType> {\n const baseType = createPrimitiveType({\n typeName: 'bigint',\n defaultValue,\n is: isBigint,\n });\n\n if (constraints === undefined || Arr.isEmpty(Object.keys(constraints))) {\n return baseType;\n }\n\n const constraintsPredicate = createConstraintsPredicate(constraints);\n\n const defaultValueConstraintsCheck = constraintsPredicate(defaultValue);\n\n if (Result.isErr(defaultValueConstraintsCheck)) {\n throw new Error(\n defaultValueErrorMessage(\n defaultValue,\n defaultValueConstraintsCheck.value,\n ),\n );\n }\n\n return refine({\n baseType,\n defaultValue,\n is: (value): value is NumberType =>\n Result.isOk(constraintsPredicate(value)),\n typeName: 'bigint',\n getConstraintDetails: (value) => {\n const result = constraintsPredicate(value);\n\n return Result.isErr(result)\n ? {\n kind: 'numeric-constraint',\n numericType: 'bigint',\n violation: result.value,\n }\n : undefined;\n },\n });\n}\n\ntype Constraints = Partial<\n Readonly<{\n nonZero: true;\n negative: true;\n nonNegative: true;\n positive: true;\n nonPositive: true;\n\n gt: NumberType;\n gte: NumberType;\n min: NumberType;\n lt: NumberType;\n lte: NumberType;\n max: NumberType;\n multipleOf: NumberType;\n step: NumberType;\n }>\n>;\n\ntype DefaultValueType<\n N extends NumberType,\n C extends Constraints,\n> = DefaultValueWhenNonZeroIsOn<N, C> &\n DefaultValueWhenNegativeIsOn<N, C> &\n DefaultValueWhenNonNegativeIsOn<N, C> &\n DefaultValueWhenPositiveIsOn<N, C> &\n DefaultValueWhenNonPositiveIsOn<N, C>;\n\ntype DefaultValueWhenNonZeroIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ nonZero: true }> ? NonZeroNumber<N> : NumberType;\n\ntype DefaultValueWhenNegativeIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ negative: true }> ? NegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenNonNegativeIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonNegative: true }> ? NonNegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenPositiveIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ positive: true }> ? PositiveNumber<N> : NumberType;\n\ntype DefaultValueWhenNonPositiveIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonPositive: true }> ? NonPositiveNumber<N> : NumberType;\n\ntype NonZeroNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsZero<N> extends true\n ? never\n : N;\n\ntype NegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNegative<N> extends true\n ? N\n : never;\n\ntype NonNegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonNegative<N> extends true\n ? N\n : never;\n\ntype PositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsPositive<N> extends true\n ? N\n : never;\n\ntype NonPositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonPositive<N> extends true\n ? N\n : never;\n\ntype IsZero<N extends NumberType> = `${N}` extends '0' ? true : false;\n\ntype IsNonZero<N extends NumberType> = IsZero<N> extends true ? false : true;\n\ntype IsNegative<N extends NumberType> = `${N}` extends `-${string}`\n ? true\n : false;\n\ntype IsNonNegative<N extends NumberType> =\n IsNegative<N> extends true ? false : true;\n\ntype IsPositive<N extends NumberType> = BoolAnd<IsNonZero<N>, IsNonNegative<N>>;\n\ntype IsNonPositive<N extends NumberType> = BoolNot<IsPositive<N>>;\n\nconst createConstraintsPredicate =\n (constraints: Constraints) =>\n (value: NumberType): Result<true, NumericConstraintViolation> => {\n const {\n nonZero,\n negative,\n nonNegative,\n positive,\n nonPositive,\n gt,\n gte,\n min,\n lt,\n lte,\n max,\n multipleOf,\n step,\n ..._rest\n } = constraints;\n\n expectType<keyof typeof _rest, never>('=');\n\n if (nonZero === true && !(value !== 0n)) {\n return Result.err({ constraint: 'nonZero', value: true } as const);\n }\n\n if (negative === true && !(value < 0n)) {\n return Result.err({ constraint: 'negative', value: true } as const);\n }\n\n if (nonNegative === true && !(value >= 0n)) {\n return Result.err({ constraint: 'nonNegative', value: true } as const);\n }\n\n if (positive === true && !(value > 0n)) {\n return Result.err({ constraint: 'positive', value: true } as const);\n }\n\n if (nonPositive === true && !(value <= 0n)) {\n return Result.err({ constraint: 'nonPositive', value: true } as const);\n }\n\n if (gt !== undefined && !(value > gt)) {\n return Result.err({ constraint: 'gt', value: gt.toString() } as const);\n }\n\n if (gte !== undefined && !(value >= gte)) {\n return Result.err({ constraint: 'gte', value: gte.toString() } as const);\n }\n\n if (min !== undefined && !(value >= min)) {\n return Result.err({ constraint: 'min', value: min.toString() } as const);\n }\n\n if (lt !== undefined && !(value < lt)) {\n return Result.err({ constraint: 'lt', value: lt.toString() } as const);\n }\n\n if (lte !== undefined && !(value <= lte)) {\n return Result.err({ constraint: 'lte', value: lte.toString() } as const);\n }\n\n if (max !== undefined && !(value <= max)) {\n return Result.err({ constraint: 'max', value: max.toString() } as const);\n }\n\n // `value % 0n` throws a RangeError, so the zero divisor is handled\n // separately: it only admits zero.\n if (multipleOf !== undefined) {\n if (multipleOf === 0n) {\n if (value !== 0n) {\n return Result.err({\n constraint: 'multipleOf',\n value: multipleOf.toString(),\n } as const);\n }\n } else if (value % multipleOf !== 0n) {\n return Result.err({\n constraint: 'multipleOf',\n value: multipleOf.toString(),\n } as const);\n }\n }\n\n if (step !== undefined) {\n if (step === 0n) {\n if (value !== 0n) {\n return Result.err({\n constraint: 'step',\n value: step.toString(),\n } as const);\n }\n } else if (value % step !== 0n) {\n return Result.err({\n constraint: 'step',\n value: step.toString(),\n } as const);\n }\n }\n\n return Result.ok(true);\n };\n\nconst defaultValueErrorMessage = (\n value: NumberType,\n violation: NumericConstraintViolation,\n): string =>\n `defaultValue [${value}] for bigint does not satisfy the constraint ${violation.constraint} = ${violation.value}` as const;\n"],"names":[],"mappings":"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"}
@@ -83,35 +83,35 @@ const createConstraintsPredicate = (constraints) => (value) => {
83
83
  return Result.err({ constraint: "nonPositive", value: true });
84
84
  }
85
85
  if (gt !== void 0 && !(value > gt)) {
86
- return Result.err({ constraint: "gt", value: String(gt) });
86
+ return Result.err({ constraint: "gt", value: gt.toString() });
87
87
  }
88
88
  if (gte !== void 0 && !(value >= gte)) {
89
- return Result.err({ constraint: "gte", value: String(gte) });
89
+ return Result.err({ constraint: "gte", value: gte.toString() });
90
90
  }
91
91
  if (min !== void 0 && !(value >= min)) {
92
- return Result.err({ constraint: "min", value: String(min) });
92
+ return Result.err({ constraint: "min", value: min.toString() });
93
93
  }
94
94
  if (lt !== void 0 && !(value < lt)) {
95
- return Result.err({ constraint: "lt", value: String(lt) });
95
+ return Result.err({ constraint: "lt", value: lt.toString() });
96
96
  }
97
97
  if (lte !== void 0 && !(value <= lte)) {
98
- return Result.err({ constraint: "lte", value: String(lte) });
98
+ return Result.err({ constraint: "lte", value: lte.toString() });
99
99
  }
100
100
  if (max !== void 0 && !(value <= max)) {
101
- return Result.err({ constraint: "max", value: String(max) });
101
+ return Result.err({ constraint: "max", value: max.toString() });
102
102
  }
103
103
  if (multipleOf !== void 0) {
104
104
  if (multipleOf === 0) {
105
105
  if (value !== 0) {
106
106
  return Result.err({
107
107
  constraint: "multipleOf",
108
- value: String(multipleOf)
108
+ value: multipleOf.toString()
109
109
  });
110
110
  }
111
111
  } else if (value % multipleOf !== 0) {
112
112
  return Result.err({
113
113
  constraint: "multipleOf",
114
- value: String(multipleOf)
114
+ value: multipleOf.toString()
115
115
  });
116
116
  }
117
117
  }
@@ -120,11 +120,14 @@ const createConstraintsPredicate = (constraints) => (value) => {
120
120
  if (value !== 0) {
121
121
  return Result.err({
122
122
  constraint: "step",
123
- value: String(step)
123
+ value: step.toString()
124
124
  });
125
125
  }
126
126
  } else if (value % step !== 0) {
127
- return Result.err({ constraint: "step", value: String(step) });
127
+ return Result.err({
128
+ constraint: "step",
129
+ value: step.toString()
130
+ });
128
131
  }
129
132
  }
130
133
  return Result.ok(true);
@@ -1 +1 @@
1
- {"version":3,"file":"number.mjs","sources":["../../src/primitives/number.mts"],"sourcesContent":["/* eslint-disable unicorn/no-negated-comparison */\nimport { Arr, expectType, Int, isNumber, Result } from 'ts-data-forge';\nimport {\n type BoolAnd,\n type BoolNot,\n type Brand,\n type FiniteNumber,\n type IsNever,\n type NegativeInt,\n type NonPositiveInt,\n type NonZeroFiniteNumber,\n type NonZeroInt,\n type PositiveInt,\n type SafeInt,\n type SafeUint,\n type StrictPick,\n type Uint,\n} from 'ts-type-forge';\nimport { refine } from '../other-types/index.mjs';\nimport { type Type } from '../type.mjs';\nimport {\n createPrimitiveType,\n type NumericConstraintViolation,\n} from '../utils/index.mjs';\n\ntype NumberType = number;\n\nexport function number(defaultValue?: NumberType): Type<NumberType>;\n\nexport function number<N extends NumberType, const C extends Constraints>(\n defaultValue: N & DefaultValueType<N, C>,\n constraints: C,\n): Type<ConstraintsToResultType<C>>;\n\nexport function number<C extends Constraints>(\n defaultValue: NumberType = 0,\n constraints?: C,\n): Type<NumberType> {\n const baseType = createPrimitiveType({\n typeName: 'number',\n defaultValue,\n is: isNumber,\n });\n\n if (constraints === undefined || Arr.isEmpty(Object.keys(constraints))) {\n return baseType;\n }\n\n const constraintsPredicate = createConstraintsPredicate(constraints);\n\n const defaultValueConstraintsCheck = constraintsPredicate(defaultValue);\n\n if (Result.isErr(defaultValueConstraintsCheck)) {\n throw new Error(\n defaultValueErrorMessage(\n defaultValue,\n defaultValueConstraintsCheck.value,\n ),\n );\n }\n\n return refine({\n baseType,\n defaultValue,\n is: (value): value is NumberType =>\n Result.isOk(constraintsPredicate(value)),\n typeName: 'number',\n getConstraintDetails: (value) => {\n const result = constraintsPredicate(value);\n\n return Result.isErr(result)\n ? {\n kind: 'numeric-constraint',\n numericType: 'number',\n violation: result.value,\n }\n : undefined;\n },\n });\n}\n\ntype Constraints = Partial<\n Readonly<{\n finite: true;\n int: true;\n safeInteger: true;\n nonZero: true;\n negative: true;\n nonNegative: true;\n positive: true;\n nonPositive: true;\n\n gt: NumberType;\n gte: NumberType;\n min: NumberType;\n lt: NumberType;\n lte: NumberType;\n max: NumberType;\n multipleOf: NumberType;\n step: NumberType;\n }>\n>;\n\n/**\n * The set of constraints accepted by {@link number}.\n */\nexport type NumberTypeConstraints = Constraints;\n\n/**\n * The numeric-range subset of {@link NumberTypeConstraints}. These constraints\n * (`gt`, `gte`, `min`, `lt`, `lte`, `max`, `multipleOf`, `step`) add runtime\n * validation without changing the result brand, so the branded number types\n * under `predefined/brand/number` accept only this subset. To build a different\n * brand from a plain number, use {@link number} with the predicate constraints\n * instead, or the dedicated branded constructor for the target type.\n */\nexport type NumberRangeConstraints = StrictPick<\n NumberTypeConstraints,\n 'gt' | 'gte' | 'min' | 'lt' | 'lte' | 'max' | 'multipleOf' | 'step'\n>;\n\ntype DefaultValueType<\n N extends NumberType,\n C extends Constraints,\n> = DefaultValueWhenNonZeroIsOn<N, C> &\n DefaultValueWhenNegativeIsOn<N, C> &\n DefaultValueWhenNonNegativeIsOn<N, C> &\n DefaultValueWhenPositiveIsOn<N, C> &\n DefaultValueWhenNonPositiveIsOn<N, C>;\n\ntype ConstraintsToResultType<C extends Constraints> =\n ConstraintsToResultHelperType<ConstraintsToResultBrandKeys<C>>;\n\ntype ConstraintsToResultHelperType<\n R extends Readonly<{ brandKeys: string; brandFalseKeys: string }>,\n> =\n IsNever<R> extends true\n ? NumberType\n : Brand<NumberType, R['brandKeys'], R['brandFalseKeys']>;\n\ntype ConstraintsToResultBrandKeys<C extends Constraints> =\n | (C extends Readonly<{ int: true }>\n ? Readonly<{ brandKeys: 'Int' | 'Finite'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ safeInteger: true }>\n ? Readonly<{\n brandKeys: 'Finite' | 'Int' | 'SafeInt';\n brandFalseKeys: 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ finite: true }>\n ? Readonly<{ brandKeys: 'Finite'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ nonZero: true }>\n ? Readonly<{ brandKeys: '!=0'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ negative: true }>\n ? Readonly<{\n brandKeys: '!=0' | '< 2^15' | '< 2^16' | '< 2^31' | '< 2^32' | '<=0';\n brandFalseKeys: '>=0' | 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ nonNegative: true }>\n ? Readonly<{\n brandKeys: '>=0' | '> -2^16' | '> -2^32' | '>= -2^15' | '>= -2^31';\n brandFalseKeys: 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ positive: true }>\n ? Readonly<{\n brandKeys:\n '>=0' | '!=0' | '> -2^16' | '> -2^32' | '>= -2^15' | '>= -2^31';\n brandFalseKeys: '<=0' | 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ nonPositive: true }>\n ? Readonly<{\n brandKeys: '< 2^15' | '< 2^16' | '< 2^31' | '< 2^32' | '<=0';\n brandFalseKeys: 'NaNValue';\n }>\n : never);\n\n{\n type BrandKeysInt = ConstraintsToResultBrandKeys<Readonly<{ int: true }>>;\n\n expectType<BrandKeysInt['brandKeys'], 'Finite' | 'Int'>('=');\n\n expectType<BrandKeysInt['brandFalseKeys'], 'NaNValue'>('=');\n\n type BrandKeysPositiveInt = ConstraintsToResultBrandKeys<\n Readonly<{ int: true; positive: true }>\n >;\n\n expectType<\n BrandKeysPositiveInt['brandKeys'],\n | 'Int'\n | 'Finite'\n | '!=0'\n | '>=0'\n | '> -2^16'\n | '> -2^32'\n | '>= -2^15'\n | '>= -2^31'\n >('=');\n\n expectType<BrandKeysPositiveInt['brandFalseKeys'], '<=0' | 'NaNValue'>('=');\n\n expectType<ConstraintsToResultType<Readonly<{ finite: true }>>, FiniteNumber>(\n '=',\n );\n\n expectType<\n ConstraintsToResultType<Readonly<{ finite: true; nonZero: true }>>,\n NonZeroFiniteNumber\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonZero: true }>>,\n NonZeroInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; positive: true }>>,\n PositiveInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; negative: true }>>,\n NegativeInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonPositive: true }>>,\n NonPositiveInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonNegative: true }>>,\n Uint\n >('=');\n\n expectType<ConstraintsToResultType<Readonly<{ safeInteger: true }>>, SafeInt>(\n '=',\n );\n\n expectType<\n ConstraintsToResultType<Readonly<{ safeInteger: true; nonNegative: true }>>,\n SafeUint\n >('=');\n}\n\ntype DefaultValueWhenNonZeroIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ nonZero: true }> ? NonZeroNumber<N> : NumberType;\n\ntype DefaultValueWhenNegativeIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ negative: true }> ? NegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenNonNegativeIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonNegative: true }> ? NonNegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenPositiveIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ positive: true }> ? PositiveNumber<N> : NumberType;\n\ntype DefaultValueWhenNonPositiveIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonPositive: true }> ? NonPositiveNumber<N> : NumberType;\n\ntype NonZeroNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsZero<N> extends true\n ? never\n : N;\n\ntype NegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNegative<N> extends true\n ? N\n : never;\n\ntype NonNegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonNegative<N> extends true\n ? N\n : never;\n\ntype PositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsPositive<N> extends true\n ? N\n : never;\n\ntype NonPositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonPositive<N> extends true\n ? N\n : never;\n\ntype IsZero<N extends NumberType> = `${N}` extends '0' ? true : false;\n\ntype IsNonZero<N extends NumberType> = IsZero<N> extends true ? false : true;\n\ntype IsNegative<N extends NumberType> = `${N}` extends `-${string}`\n ? true\n : false;\n\ntype IsNonNegative<N extends NumberType> =\n IsNegative<N> extends true ? false : true;\n\ntype IsPositive<N extends NumberType> = BoolAnd<IsNonZero<N>, IsNonNegative<N>>;\n\ntype IsNonPositive<N extends NumberType> = BoolNot<IsPositive<N>>;\n\nconst createConstraintsPredicate =\n (constraints: Constraints) =>\n (value: NumberType): Result<true, NumericConstraintViolation> => {\n const {\n finite,\n int,\n safeInteger,\n nonZero,\n negative,\n nonNegative,\n positive,\n nonPositive,\n gt,\n gte,\n min,\n lt,\n lte,\n max,\n multipleOf,\n step,\n ..._rest\n } = constraints;\n\n expectType<keyof typeof _rest, never>('=');\n\n if (finite === true && !Number.isFinite(value)) {\n return Result.err({ constraint: 'finite', value: true } as const);\n }\n\n if (int === true && !Int.is(value)) {\n return Result.err({ constraint: 'int', value: true } as const);\n }\n\n if (safeInteger === true && !Number.isSafeInteger(value)) {\n return Result.err({ constraint: 'safeInteger', value: true } as const);\n }\n\n if (nonZero === true && !(value !== 0)) {\n return Result.err({ constraint: 'nonZero', value: true } as const);\n }\n\n if (negative === true && !(value < 0)) {\n return Result.err({ constraint: 'negative', value: true } as const);\n }\n\n if (nonNegative === true && !(value >= 0)) {\n return Result.err({ constraint: 'nonNegative', value: true } as const);\n }\n\n if (positive === true && !(value > 0)) {\n return Result.err({ constraint: 'positive', value: true } as const);\n }\n\n if (nonPositive === true && !(value <= 0)) {\n return Result.err({ constraint: 'nonPositive', value: true } as const);\n }\n\n if (gt !== undefined && !(value > gt)) {\n return Result.err({ constraint: 'gt', value: String(gt) } as const);\n }\n\n if (gte !== undefined && !(value >= gte)) {\n return Result.err({ constraint: 'gte', value: String(gte) } as const);\n }\n\n if (min !== undefined && !(value >= min)) {\n return Result.err({ constraint: 'min', value: String(min) } as const);\n }\n\n if (lt !== undefined && !(value < lt)) {\n return Result.err({ constraint: 'lt', value: String(lt) } as const);\n }\n\n if (lte !== undefined && !(value <= lte)) {\n return Result.err({ constraint: 'lte', value: String(lte) } as const);\n }\n\n if (max !== undefined && !(value <= max)) {\n return Result.err({ constraint: 'max', value: String(max) } as const);\n }\n\n // `value % 0` throws a RangeError, so the zero divisor is handled\n // separately: it only admits zero.\n if (multipleOf !== undefined) {\n if (multipleOf === 0) {\n if (value !== 0) {\n return Result.err({\n constraint: 'multipleOf',\n value: String(multipleOf),\n } as const);\n }\n } else if (value % multipleOf !== 0) {\n return Result.err({\n constraint: 'multipleOf',\n value: String(multipleOf),\n } as const);\n }\n }\n\n if (step !== undefined) {\n if (step === 0) {\n if (value !== 0) {\n return Result.err({\n constraint: 'step',\n value: String(step),\n } as const);\n }\n } else if (value % step !== 0) {\n return Result.err({ constraint: 'step', value: String(step) } as const);\n }\n }\n\n return Result.ok(true);\n };\n\nconst defaultValueErrorMessage = (\n value: NumberType,\n violation: NumericConstraintViolation,\n): string =>\n `defaultValue [${value}] for number does not satisfy the constraint ${violation.constraint} = ${violation.value}` as const;\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"number.mjs","sources":["../../src/primitives/number.mts"],"sourcesContent":["/* eslint-disable unicorn/no-negated-comparison */\nimport { Arr, expectType, Int, isNumber, Result } from 'ts-data-forge';\nimport {\n type BoolAnd,\n type BoolNot,\n type Brand,\n type FiniteNumber,\n type IsNever,\n type NegativeInt,\n type NonPositiveInt,\n type NonZeroFiniteNumber,\n type NonZeroInt,\n type PositiveInt,\n type SafeInt,\n type SafeUint,\n type StrictPick,\n type Uint,\n} from 'ts-type-forge';\nimport { refine } from '../other-types/index.mjs';\nimport { type Type } from '../type.mjs';\nimport {\n createPrimitiveType,\n type NumericConstraintViolation,\n} from '../utils/index.mjs';\n\ntype NumberType = number;\n\nexport function number(defaultValue?: NumberType): Type<NumberType>;\n\nexport function number<N extends NumberType, const C extends Constraints>(\n defaultValue: N & DefaultValueType<N, C>,\n constraints: C,\n): Type<ConstraintsToResultType<C>>;\n\nexport function number<C extends Constraints>(\n defaultValue: NumberType = 0,\n constraints?: C,\n): Type<NumberType> {\n const baseType = createPrimitiveType({\n typeName: 'number',\n defaultValue,\n is: isNumber,\n });\n\n if (constraints === undefined || Arr.isEmpty(Object.keys(constraints))) {\n return baseType;\n }\n\n const constraintsPredicate = createConstraintsPredicate(constraints);\n\n const defaultValueConstraintsCheck = constraintsPredicate(defaultValue);\n\n if (Result.isErr(defaultValueConstraintsCheck)) {\n throw new Error(\n defaultValueErrorMessage(\n defaultValue,\n defaultValueConstraintsCheck.value,\n ),\n );\n }\n\n return refine({\n baseType,\n defaultValue,\n is: (value): value is NumberType =>\n Result.isOk(constraintsPredicate(value)),\n typeName: 'number',\n getConstraintDetails: (value) => {\n const result = constraintsPredicate(value);\n\n return Result.isErr(result)\n ? {\n kind: 'numeric-constraint',\n numericType: 'number',\n violation: result.value,\n }\n : undefined;\n },\n });\n}\n\ntype Constraints = Partial<\n Readonly<{\n finite: true;\n int: true;\n safeInteger: true;\n nonZero: true;\n negative: true;\n nonNegative: true;\n positive: true;\n nonPositive: true;\n\n gt: NumberType;\n gte: NumberType;\n min: NumberType;\n lt: NumberType;\n lte: NumberType;\n max: NumberType;\n multipleOf: NumberType;\n step: NumberType;\n }>\n>;\n\n/**\n * The set of constraints accepted by {@link number}.\n */\nexport type NumberTypeConstraints = Constraints;\n\n/**\n * The numeric-range subset of {@link NumberTypeConstraints}. These constraints\n * (`gt`, `gte`, `min`, `lt`, `lte`, `max`, `multipleOf`, `step`) add runtime\n * validation without changing the result brand, so the branded number types\n * under `predefined/brand/number` accept only this subset. To build a different\n * brand from a plain number, use {@link number} with the predicate constraints\n * instead, or the dedicated branded constructor for the target type.\n */\nexport type NumberRangeConstraints = StrictPick<\n NumberTypeConstraints,\n 'gt' | 'gte' | 'min' | 'lt' | 'lte' | 'max' | 'multipleOf' | 'step'\n>;\n\ntype DefaultValueType<\n N extends NumberType,\n C extends Constraints,\n> = DefaultValueWhenNonZeroIsOn<N, C> &\n DefaultValueWhenNegativeIsOn<N, C> &\n DefaultValueWhenNonNegativeIsOn<N, C> &\n DefaultValueWhenPositiveIsOn<N, C> &\n DefaultValueWhenNonPositiveIsOn<N, C>;\n\ntype ConstraintsToResultType<C extends Constraints> =\n ConstraintsToResultHelperType<ConstraintsToResultBrandKeys<C>>;\n\ntype ConstraintsToResultHelperType<\n R extends Readonly<{ brandKeys: string; brandFalseKeys: string }>,\n> =\n IsNever<R> extends true\n ? NumberType\n : Brand<NumberType, R['brandKeys'], R['brandFalseKeys']>;\n\ntype ConstraintsToResultBrandKeys<C extends Constraints> =\n | (C extends Readonly<{ int: true }>\n ? Readonly<{ brandKeys: 'Int' | 'Finite'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ safeInteger: true }>\n ? Readonly<{\n brandKeys: 'Finite' | 'Int' | 'SafeInt';\n brandFalseKeys: 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ finite: true }>\n ? Readonly<{ brandKeys: 'Finite'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ nonZero: true }>\n ? Readonly<{ brandKeys: '!=0'; brandFalseKeys: 'NaNValue' }>\n : never)\n | (C extends Readonly<{ negative: true }>\n ? Readonly<{\n brandKeys: '!=0' | '< 2^15' | '< 2^16' | '< 2^31' | '< 2^32' | '<=0';\n brandFalseKeys: '>=0' | 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ nonNegative: true }>\n ? Readonly<{\n brandKeys: '>=0' | '> -2^16' | '> -2^32' | '>= -2^15' | '>= -2^31';\n brandFalseKeys: 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ positive: true }>\n ? Readonly<{\n brandKeys:\n '>=0' | '!=0' | '> -2^16' | '> -2^32' | '>= -2^15' | '>= -2^31';\n brandFalseKeys: '<=0' | 'NaNValue';\n }>\n : never)\n | (C extends Readonly<{ nonPositive: true }>\n ? Readonly<{\n brandKeys: '< 2^15' | '< 2^16' | '< 2^31' | '< 2^32' | '<=0';\n brandFalseKeys: 'NaNValue';\n }>\n : never);\n\n{\n type BrandKeysInt = ConstraintsToResultBrandKeys<Readonly<{ int: true }>>;\n\n expectType<BrandKeysInt['brandKeys'], 'Finite' | 'Int'>('=');\n\n expectType<BrandKeysInt['brandFalseKeys'], 'NaNValue'>('=');\n\n type BrandKeysPositiveInt = ConstraintsToResultBrandKeys<\n Readonly<{ int: true; positive: true }>\n >;\n\n expectType<\n BrandKeysPositiveInt['brandKeys'],\n | 'Int'\n | 'Finite'\n | '!=0'\n | '>=0'\n | '> -2^16'\n | '> -2^32'\n | '>= -2^15'\n | '>= -2^31'\n >('=');\n\n expectType<BrandKeysPositiveInt['brandFalseKeys'], '<=0' | 'NaNValue'>('=');\n\n expectType<ConstraintsToResultType<Readonly<{ finite: true }>>, FiniteNumber>(\n '=',\n );\n\n expectType<\n ConstraintsToResultType<Readonly<{ finite: true; nonZero: true }>>,\n NonZeroFiniteNumber\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonZero: true }>>,\n NonZeroInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; positive: true }>>,\n PositiveInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; negative: true }>>,\n NegativeInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonPositive: true }>>,\n NonPositiveInt\n >('=');\n\n expectType<\n ConstraintsToResultType<Readonly<{ int: true; nonNegative: true }>>,\n Uint\n >('=');\n\n expectType<ConstraintsToResultType<Readonly<{ safeInteger: true }>>, SafeInt>(\n '=',\n );\n\n expectType<\n ConstraintsToResultType<Readonly<{ safeInteger: true; nonNegative: true }>>,\n SafeUint\n >('=');\n}\n\ntype DefaultValueWhenNonZeroIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ nonZero: true }> ? NonZeroNumber<N> : NumberType;\n\ntype DefaultValueWhenNegativeIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ negative: true }> ? NegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenNonNegativeIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonNegative: true }> ? NonNegativeNumber<N> : NumberType;\n\ntype DefaultValueWhenPositiveIsOn<N extends NumberType, C extends Constraints> =\n C extends Readonly<{ positive: true }> ? PositiveNumber<N> : NumberType;\n\ntype DefaultValueWhenNonPositiveIsOn<\n N extends NumberType,\n C extends Constraints,\n> =\n C extends Readonly<{ nonPositive: true }> ? NonPositiveNumber<N> : NumberType;\n\ntype NonZeroNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsZero<N> extends true\n ? never\n : N;\n\ntype NegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNegative<N> extends true\n ? N\n : never;\n\ntype NonNegativeNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonNegative<N> extends true\n ? N\n : never;\n\ntype PositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsPositive<N> extends true\n ? N\n : never;\n\ntype NonPositiveNumber<N extends NumberType> = NumberType extends N\n ? NumberType\n : IsNonPositive<N> extends true\n ? N\n : never;\n\ntype IsZero<N extends NumberType> = `${N}` extends '0' ? true : false;\n\ntype IsNonZero<N extends NumberType> = IsZero<N> extends true ? false : true;\n\ntype IsNegative<N extends NumberType> = `${N}` extends `-${string}`\n ? true\n : false;\n\ntype IsNonNegative<N extends NumberType> =\n IsNegative<N> extends true ? false : true;\n\ntype IsPositive<N extends NumberType> = BoolAnd<IsNonZero<N>, IsNonNegative<N>>;\n\ntype IsNonPositive<N extends NumberType> = BoolNot<IsPositive<N>>;\n\nconst createConstraintsPredicate =\n (constraints: Constraints) =>\n (value: NumberType): Result<true, NumericConstraintViolation> => {\n const {\n finite,\n int,\n safeInteger,\n nonZero,\n negative,\n nonNegative,\n positive,\n nonPositive,\n gt,\n gte,\n min,\n lt,\n lte,\n max,\n multipleOf,\n step,\n ..._rest\n } = constraints;\n\n expectType<keyof typeof _rest, never>('=');\n\n if (finite === true && !Number.isFinite(value)) {\n return Result.err({ constraint: 'finite', value: true } as const);\n }\n\n if (int === true && !Int.is(value)) {\n return Result.err({ constraint: 'int', value: true } as const);\n }\n\n if (safeInteger === true && !Number.isSafeInteger(value)) {\n return Result.err({ constraint: 'safeInteger', value: true } as const);\n }\n\n if (nonZero === true && !(value !== 0)) {\n return Result.err({ constraint: 'nonZero', value: true } as const);\n }\n\n if (negative === true && !(value < 0)) {\n return Result.err({ constraint: 'negative', value: true } as const);\n }\n\n if (nonNegative === true && !(value >= 0)) {\n return Result.err({ constraint: 'nonNegative', value: true } as const);\n }\n\n if (positive === true && !(value > 0)) {\n return Result.err({ constraint: 'positive', value: true } as const);\n }\n\n if (nonPositive === true && !(value <= 0)) {\n return Result.err({ constraint: 'nonPositive', value: true } as const);\n }\n\n if (gt !== undefined && !(value > gt)) {\n return Result.err({ constraint: 'gt', value: gt.toString() } as const);\n }\n\n if (gte !== undefined && !(value >= gte)) {\n return Result.err({ constraint: 'gte', value: gte.toString() } as const);\n }\n\n if (min !== undefined && !(value >= min)) {\n return Result.err({ constraint: 'min', value: min.toString() } as const);\n }\n\n if (lt !== undefined && !(value < lt)) {\n return Result.err({ constraint: 'lt', value: lt.toString() } as const);\n }\n\n if (lte !== undefined && !(value <= lte)) {\n return Result.err({ constraint: 'lte', value: lte.toString() } as const);\n }\n\n if (max !== undefined && !(value <= max)) {\n return Result.err({ constraint: 'max', value: max.toString() } as const);\n }\n\n // `value % 0` throws a RangeError, so the zero divisor is handled\n // separately: it only admits zero.\n if (multipleOf !== undefined) {\n if (multipleOf === 0) {\n if (value !== 0) {\n return Result.err({\n constraint: 'multipleOf',\n value: multipleOf.toString(),\n } as const);\n }\n } else if (value % multipleOf !== 0) {\n return Result.err({\n constraint: 'multipleOf',\n value: multipleOf.toString(),\n } as const);\n }\n }\n\n if (step !== undefined) {\n if (step === 0) {\n if (value !== 0) {\n return Result.err({\n constraint: 'step',\n value: step.toString(),\n } as const);\n }\n } else if (value % step !== 0) {\n return Result.err({\n constraint: 'step',\n value: step.toString(),\n } as const);\n }\n }\n\n return Result.ok(true);\n };\n\nconst defaultValueErrorMessage = (\n value: NumberType,\n violation: NumericConstraintViolation,\n): string =>\n `defaultValue [${value}] for number does not satisfy the constraint ${violation.constraint} = ${violation.value}` as const;\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"key-value-record.d.mts","sourceRoot":"","sources":["../../src/record/key-value-record.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAUnE,KAAK,gBAAgB,CACnB,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,EACtB,CAAC,SAAS,OAAO,IACf,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzC,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,OAAO,WAC7D,CAAC,aACC,CAAC,YACF,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAqG7B,CAAC"}
1
+ {"version":3,"file":"key-value-record.d.mts","sourceRoot":"","sources":["../../src/record/key-value-record.mts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AAUnE,KAAK,gBAAgB,CACnB,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,EACtB,CAAC,SAAS,OAAO,IACf,cAAc,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAEzC,eAAO,MAAM,cAAc,GAAI,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,SAAS,OAAO,WAC7D,CAAC,aACC,CAAC,YACF,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC,CACH,KACA,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CA+F7B,CAAC"}
@@ -1,4 +1,4 @@
1
- import { isRecord, Result, Arr, tp } from 'ts-data-forge';
1
+ import { isRecord, Result, Arr, Obj, Optional } from 'ts-data-forge';
2
2
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
3
3
  import { createCastFn } from '../utils/create-cast-fn.mjs';
4
4
  import { createIsFn } from '../utils/create-is-fn.mjs';
@@ -63,16 +63,13 @@ const keyValueRecord = (keyType, valueType, options) => {
63
63
  };
64
64
  const fill = (a) => isRecord(a) ? (
65
65
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
66
- Object.fromEntries(
67
- Object.entries(a).filter(
68
- ([k, v]) => keyType.is(k) && valueType.is(v)
69
- )
70
- )
66
+ Obj.filter(a, (v, k) => keyType.is(k) && valueType.is(v))
71
67
  ) : defaultValue;
72
68
  const prune = (a) => (
73
69
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
74
- Object.fromEntries(
75
- Object.entries(a).filter(([k]) => keyType.is(k)).map(([k, v]) => tp(k, valueType.prune(v)))
70
+ Obj.filterMap(
71
+ a,
72
+ (v, k) => keyType.is(k) ? Optional.some(valueType.prune(v)) : Optional.none
76
73
  )
77
74
  );
78
75
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"key-value-record.mjs","sources":["../../src/record/key-value-record.mts"],"sourcesContent":["import { Arr, isRecord, Result, tp } from 'ts-data-forge';\nimport { type ReadonlyRecord } from 'ts-type-forge';\nimport { type AnyType, type Type, type TypeOf } from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n createPrimitiveValidationError,\n prependPathToValidationErrors,\n type ValidationError,\n} from '../utils/index.mjs';\n\ntype RecordResultType<\n K extends Type<string>,\n V extends AnyType,\n> = ReadonlyRecord<TypeOf<K>, TypeOf<V>>;\n\nexport const keyValueRecord = <K extends Type<string>, V extends AnyType>(\n keyType: K,\n valueType: V,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): Type<RecordResultType<K, V>> => {\n type T = RecordResultType<K, V>;\n\n const typeName = options?.typeName ?? 'key-value-record';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n const defaultValue = {} as T;\n\n const validate: Type<T>['validate'] = (a) => {\n if (!isRecord(a)) {\n return Result.err([\n createPrimitiveValidationError({\n actualValue: a,\n expectedType: 'record',\n typeName,\n details: undefined,\n }),\n ]);\n }\n\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const [k, v] of Object.entries(a)) {\n {\n const res = keyType.validate(k);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: k,\n expectedType: typeName,\n typeName,\n details: {\n kind: 'record-entry',\n entry: 'key',\n expectedType: keyType.typeName,\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n\n {\n const res = valueType.validate(v);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: v,\n expectedType: typeName,\n typeName,\n details: {\n kind: 'record-entry',\n entry: 'value',\n expectedType: valueType.typeName,\n },\n } satisfies ValidationError;\n\n yield* prependPathToValidationErrors(res.value, k);\n }\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const fill: Type<T>['fill'] = (a) =>\n isRecord(a)\n ? // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (Object.fromEntries(\n Object.entries(a).filter(\n ([k, v]) => keyType.is(k) && valueType.is(v),\n ),\n ) as T)\n : defaultValue;\n\n // Keys not matching keyType are excess paths; values are pruned recursively.\n const prune = (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(a)\n .filter(([k]) => keyType.is(k))\n .map(([k, v]) => tp(k, valueType.prune(v))),\n ) as T;\n\n return {\n typeName,\n defaultValue,\n fill,\n prune,\n validate,\n is: createIsFn(validate),\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n };\n};\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"key-value-record.mjs","sources":["../../src/record/key-value-record.mts"],"sourcesContent":["import { Arr, isRecord, Obj, Optional, Result } from 'ts-data-forge';\nimport { type ReadonlyRecord } from 'ts-type-forge';\nimport { type AnyType, type Type, type TypeOf } from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n createPrimitiveValidationError,\n prependPathToValidationErrors,\n type ValidationError,\n} from '../utils/index.mjs';\n\ntype RecordResultType<\n K extends Type<string>,\n V extends AnyType,\n> = ReadonlyRecord<TypeOf<K>, TypeOf<V>>;\n\nexport const keyValueRecord = <K extends Type<string>, V extends AnyType>(\n keyType: K,\n valueType: V,\n options?: Partial<\n Readonly<{\n typeName: string;\n }>\n >,\n): Type<RecordResultType<K, V>> => {\n type T = RecordResultType<K, V>;\n\n const typeName = options?.typeName ?? 'key-value-record';\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n const defaultValue = {} as T;\n\n const validate: Type<T>['validate'] = (a) => {\n if (!isRecord(a)) {\n return Result.err([\n createPrimitiveValidationError({\n actualValue: a,\n expectedType: 'record',\n typeName,\n details: undefined,\n }),\n ]);\n }\n\n const errors: readonly ValidationError[] = Arr.generate(function* () {\n for (const [k, v] of Object.entries(a)) {\n {\n const res = keyType.validate(k);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: k,\n expectedType: typeName,\n typeName,\n details: {\n kind: 'record-entry',\n entry: 'key',\n expectedType: keyType.typeName,\n },\n } satisfies ValidationError;\n\n yield* res.value;\n }\n }\n\n {\n const res = valueType.validate(v);\n\n if (Result.isErr(res)) {\n yield {\n path: [],\n actualValue: v,\n expectedType: typeName,\n typeName,\n details: {\n kind: 'record-entry',\n entry: 'value',\n expectedType: valueType.typeName,\n },\n } satisfies ValidationError;\n\n yield* prependPathToValidationErrors(res.value, k);\n }\n }\n }\n });\n\n if (Arr.isNonEmpty(errors)) {\n return Result.err(errors);\n }\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Result.ok(a as T);\n };\n\n const fill: Type<T>['fill'] = (a) =>\n isRecord(a)\n ? // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n (Obj.filter(a, (v, k) => keyType.is(k) && valueType.is(v)) as T)\n : defaultValue;\n\n // Keys not matching keyType are excess paths; values are pruned recursively.\n const prune = (a: T): T =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Obj.filterMap(a, (v, k) =>\n keyType.is(k) ? Optional.some(valueType.prune(v)) : Optional.none,\n ) as T;\n\n return {\n typeName,\n defaultValue,\n fill,\n prune,\n validate,\n is: createIsFn(validate),\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n };\n};\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"partial.d.mts","sourceRoot":"","sources":["../../src/record/partial.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,IAAI,EAKV,MAAM,aAAa,CAAC;AAKrB;;;GAGG;AACH,eAAO,MAAM,OAAO,GAClB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,cAElD,IAAI,CAAC,CAAC,CAAC,YACT,OAAO,CACf,QAAQ,CAAC;IACP,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC,CACH,KACA,WAAW,CAAC,CAAC,EAAE,gBAAgB,CAoCjC,CAAC;AAEF,KAAK,WAAW,CACd,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,GAClE,SAAS,IACT,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE5C,sCAAsC;AACtC,KAAK,YAAY,CACf,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,IAEpE,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,SAAS,IAAI,GAC5C,OAAO,CAAC,CAAC,CAAC,GACV,gBAAgB,CAAC,CAAC,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"partial.d.mts","sourceRoot":"","sources":["../../src/record/partial.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,gBAAgB,EACrB,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,oBAAoB,EACzB,KAAK,IAAI,EAKV,MAAM,aAAa,CAAC;AAKrB;;;GAGG;AACH,eAAO,MAAM,OAAO,GAClB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,cAElD,IAAI,CAAC,CAAC,CAAC,YACT,OAAO,CACf,QAAQ,CAAC;IACP,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC,CACH,KACA,WAAW,CAAC,CAAC,EAAE,gBAAgB,CAkCjC,CAAC;AAEF,KAAK,WAAW,CACd,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,GAClE,SAAS,IACT,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE5C,sCAAsC;AACtC,KAAK,YAAY,CACf,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,IAEpE,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,SAAS,IAAI,GAC5C,OAAO,CAAC,CAAC,CAAC,GACV,gBAAgB,CAAC,CAAC,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
- import 'ts-data-forge';
1
+ import { Obj } from 'ts-data-forge';
2
2
  import { hasRecordInternals, flattenShapeStructure } from '../type.mjs';
3
3
  import '@sindresorhus/is';
4
4
  import { toUnionKeyString } from '../utils/to-union-string.mjs';
@@ -21,10 +21,9 @@ const partial = (recordType, options) => {
21
21
  const keysToBeOptional = new Set(
22
22
  options?.keysToBeOptional ?? Object.keys(shape)
23
23
  );
24
- const partialShape = Object.fromEntries(
25
- Object.entries(shape).map(
26
- ([k, v]) => [k, keysToBeOptional.has(k) ? optional(v) : v]
27
- )
24
+ const partialShape = Obj.map(
25
+ shape,
26
+ (v, k) => keysToBeOptional.has(k) ? optional(v) : v
28
27
  );
29
28
  return record(partialShape, {
30
29
  typeName: typeNameFilled,
@@ -1 +1 @@
1
- {"version":3,"file":"partial.mjs","sources":["../../src/record/partial.mts"],"sourcesContent":["import { expectType } from 'ts-data-forge';\nimport {\n type ArrayElement,\n type NonEmptyTuple,\n type PartiallyPartial,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n type UnknownShape,\n flattenShapeStructure,\n hasRecordInternals,\n} from '../type.mjs';\nimport { toUnionKeyString } from '../utils/index.mjs';\nimport { optional } from './optional.mjs';\nimport { record } from './record.mjs';\n\n/**\n * Creates a Partial type. If keysToBeOptional is set, only those keys are\n * optional, otherwise, all properties are optional.\n */\nexport const partial = <\n const R extends UnknownRecord,\n const KeysToBeOptional extends NonEmptyTuple<keyof R & string>,\n>(\n recordType: Type<R>,\n options?: Partial<\n Readonly<{\n keysToBeOptional: KeysToBeOptional;\n typeName: string;\n excessProperty: ExcessPropertyOption;\n }>\n >,\n): PartialType<R, KeysToBeOptional> => {\n if (!hasRecordInternals(recordType)) {\n throw new Error(\n `Expected a record type but received: ${recordType.typeName}`,\n );\n }\n\n const shape = flattenShapeStructure(recordType.shapeStructure);\n\n if (shape === undefined) {\n throw new Error(\n `partial() requires a simple or intersection record type, but received a union type`,\n );\n }\n\n const typeNameFilled: string =\n options?.typeName ??\n (options?.keysToBeOptional === undefined\n ? `Partial<${recordType.typeName}>`\n : `PartiallyPartial<${recordType.typeName}, ${toUnionKeyString(options.keysToBeOptional)}>`);\n\n const keysToBeOptional: ReadonlySet<string> = new Set(\n options?.keysToBeOptional ?? Object.keys(shape),\n );\n\n const partialShape = Object.fromEntries(\n Object.entries(shape).map(\n ([k, v]) => [k, keysToBeOptional.has(k) ? optional(v) : v] as const,\n ),\n ) satisfies UnknownShape;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return record(partialShape, {\n typeName: typeNameFilled,\n excessProperty: options?.excessProperty ?? recordType.excessProperty,\n }) as unknown as PartialType<R, KeysToBeOptional>;\n};\n\ntype PartialType<\n R extends UnknownRecord,\n KeysToBeOptional extends NonEmptyTuple<keyof R & string> | undefined =\n undefined,\n> = Type<PartialValue<R, KeysToBeOptional>>;\n\n/** Compute the partial value type. */\ntype PartialValue<\n R extends UnknownRecord,\n KeysToBeOptional extends NonEmptyTuple<keyof R & string> | undefined,\n> =\n TypeEq<KeysToBeOptional, undefined> extends true\n ? Partial<R>\n : PartiallyPartial<R, ArrayElement<KeysToBeOptional>>;\n\n// --- expectType assertions ---\n\n{\n type Base = ReturnType<\n typeof record<Readonly<{ a: Type<0>; b: Type<1>; c: Type<2> }>>\n >;\n\n expectType<\n PartialType<TypeOf<Base>, readonly ['a', 'b', 'c']>,\n Type<Partial<Readonly<{ a: 0; b: 1; c: 2 }>>>\n >('=');\n\n expectType<\n PartialType<TypeOf<Base>, readonly ['a', 'b']>,\n Type<Readonly<{ a?: 0; b?: 1; c: 2 }>>\n >('=');\n\n expectType<\n // @ts-expect-error NonEmptyTuple is required if keysToBeOptional is provided\n PartialType<TypeOf<Base>, readonly []>,\n Type<Readonly<{ a?: 0; b?: 1; c: 2 }>>\n >('!=');\n\n expectType<\n PartialType<TypeOf<Base>>,\n Type<Readonly<{ a?: 0; b?: 1; c?: 2 }>>\n >('=');\n\n // partial with no keys makes all properties optional\n expectType<\n TypeOf<\n ReturnType<typeof partial<TypeOf<Base>, NonEmptyTuple<'a' | 'b' | 'c'>>>\n >,\n Partial<Readonly<{ a: 0; b: 1; c: 2 }>>\n >('=');\n}\n"],"names":[],"mappings":";;;;;;;MAwBa,OAAA,GAAU,CAIrB,UAAA,EACA,OAAA,KAOqC;AACrC,EAAA,IAAI,CAAC,kBAAA,CAAmB,UAAU,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qCAAA,EAAwC,WAAW,QAAQ,CAAA;AAAA,KAC7D;AAAA,EAAA;AAGF,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,UAAA,CAAW,cAAc,CAAA;AAE7D,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,kFAAA;AAAA,KACF;AAAA,EAAA;AAGF,EAAA,MAAM,iBACJ,OAAA,EAAS,QAAA,KACR,OAAA,EAAS,gBAAA,KAAqB,SAC3B,CAAA,QAAA,EAAW,UAAA,CAAW,QAAQ,CAAA,CAAA,CAAA,GAC9B,oBAAoB,UAAA,CAAW,QAAQ,KAAK,gBAAA,CAAiB,OAAA,CAAQ,gBAAgB,CAAC,CAAA,CAAA,CAAA,CAAA;AAE5F,EAAA,MAAM,mBAAwC,IAAI,GAAA;AAAA,IAChD,OAAA,EAAS,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAK,KAAK;AAAA,GAChD;AAEA,EAAA,MAAM,eAAe,MAAA,CAAO,WAAA;AAAA,IAC1B,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,GAAA;AAAA,MACpB,CAAC,CAAC,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA,EAAG,gBAAA,CAAiB,GAAA,CAAI,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,IAAI,CAAC;AAAA;AAC3D,GACF;AAGA,EAAA,OAAO,OAAO,YAAA,EAAc;AAAA,IAC1B,QAAA,EAAU,cAAA;AAAA,IACV,cAAA,EAAgB,OAAA,EAAS,cAAA,IAAkB,UAAA,CAAW;AAAA,GACvD,CAAA;AACH;;;;"}
1
+ {"version":3,"file":"partial.mjs","sources":["../../src/record/partial.mts"],"sourcesContent":["import { Obj, expectType } from 'ts-data-forge';\nimport {\n type ArrayElement,\n type NonEmptyTuple,\n type PartiallyPartial,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n type UnknownShape,\n flattenShapeStructure,\n hasRecordInternals,\n} from '../type.mjs';\nimport { toUnionKeyString } from '../utils/index.mjs';\nimport { optional } from './optional.mjs';\nimport { record } from './record.mjs';\n\n/**\n * Creates a Partial type. If keysToBeOptional is set, only those keys are\n * optional, otherwise, all properties are optional.\n */\nexport const partial = <\n const R extends UnknownRecord,\n const KeysToBeOptional extends NonEmptyTuple<keyof R & string>,\n>(\n recordType: Type<R>,\n options?: Partial<\n Readonly<{\n keysToBeOptional: KeysToBeOptional;\n typeName: string;\n excessProperty: ExcessPropertyOption;\n }>\n >,\n): PartialType<R, KeysToBeOptional> => {\n if (!hasRecordInternals(recordType)) {\n throw new Error(\n `Expected a record type but received: ${recordType.typeName}`,\n );\n }\n\n const shape = flattenShapeStructure(recordType.shapeStructure);\n\n if (shape === undefined) {\n throw new Error(\n `partial() requires a simple or intersection record type, but received a union type`,\n );\n }\n\n const typeNameFilled: string =\n options?.typeName ??\n (options?.keysToBeOptional === undefined\n ? `Partial<${recordType.typeName}>`\n : `PartiallyPartial<${recordType.typeName}, ${toUnionKeyString(options.keysToBeOptional)}>`);\n\n const keysToBeOptional: ReadonlySet<string> = new Set(\n options?.keysToBeOptional ?? Object.keys(shape),\n );\n\n const partialShape = Obj.map(shape, (v, k) =>\n keysToBeOptional.has(k) ? optional(v) : v,\n ) satisfies UnknownShape;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return record(partialShape, {\n typeName: typeNameFilled,\n excessProperty: options?.excessProperty ?? recordType.excessProperty,\n }) as unknown as PartialType<R, KeysToBeOptional>;\n};\n\ntype PartialType<\n R extends UnknownRecord,\n KeysToBeOptional extends NonEmptyTuple<keyof R & string> | undefined =\n undefined,\n> = Type<PartialValue<R, KeysToBeOptional>>;\n\n/** Compute the partial value type. */\ntype PartialValue<\n R extends UnknownRecord,\n KeysToBeOptional extends NonEmptyTuple<keyof R & string> | undefined,\n> =\n TypeEq<KeysToBeOptional, undefined> extends true\n ? Partial<R>\n : PartiallyPartial<R, ArrayElement<KeysToBeOptional>>;\n\n// --- expectType assertions ---\n\n{\n type Base = ReturnType<\n typeof record<Readonly<{ a: Type<0>; b: Type<1>; c: Type<2> }>>\n >;\n\n expectType<\n PartialType<TypeOf<Base>, readonly ['a', 'b', 'c']>,\n Type<Partial<Readonly<{ a: 0; b: 1; c: 2 }>>>\n >('=');\n\n expectType<\n PartialType<TypeOf<Base>, readonly ['a', 'b']>,\n Type<Readonly<{ a?: 0; b?: 1; c: 2 }>>\n >('=');\n\n expectType<\n // @ts-expect-error NonEmptyTuple is required if keysToBeOptional is provided\n PartialType<TypeOf<Base>, readonly []>,\n Type<Readonly<{ a?: 0; b?: 1; c: 2 }>>\n >('!=');\n\n expectType<\n PartialType<TypeOf<Base>>,\n Type<Readonly<{ a?: 0; b?: 1; c?: 2 }>>\n >('=');\n\n // partial with no keys makes all properties optional\n expectType<\n TypeOf<\n ReturnType<typeof partial<TypeOf<Base>, NonEmptyTuple<'a' | 'b' | 'c'>>>\n >,\n Partial<Readonly<{ a: 0; b: 1; c: 2 }>>\n >('=');\n}\n"],"names":[],"mappings":";;;;;;;MAwBa,OAAA,GAAU,CAIrB,UAAA,EACA,OAAA,KAOqC;AACrC,EAAA,IAAI,CAAC,kBAAA,CAAmB,UAAU,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qCAAA,EAAwC,WAAW,QAAQ,CAAA;AAAA,KAC7D;AAAA,EAAA;AAGF,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,UAAA,CAAW,cAAc,CAAA;AAE7D,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,kFAAA;AAAA,KACF;AAAA,EAAA;AAGF,EAAA,MAAM,iBACJ,OAAA,EAAS,QAAA,KACR,OAAA,EAAS,gBAAA,KAAqB,SAC3B,CAAA,QAAA,EAAW,UAAA,CAAW,QAAQ,CAAA,CAAA,CAAA,GAC9B,oBAAoB,UAAA,CAAW,QAAQ,KAAK,gBAAA,CAAiB,OAAA,CAAQ,gBAAgB,CAAC,CAAA,CAAA,CAAA,CAAA;AAE5F,EAAA,MAAM,mBAAwC,IAAI,GAAA;AAAA,IAChD,OAAA,EAAS,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAK,KAAK;AAAA,GAChD;AAEA,EAAA,MAAM,eAAe,GAAA,CAAI,GAAA;AAAA,IAAI,KAAA;AAAA,IAAO,CAAC,GAAG,CAAA,KACtC,gBAAA,CAAiB,IAAI,CAAC,CAAA,GAAI,QAAA,CAAS,CAAC,CAAA,GAAI;AAAA,GAC1C;AAGA,EAAA,OAAO,OAAO,YAAA,EAAc;AAAA,IAC1B,QAAA,EAAU,cAAA;AAAA,IACV,cAAA,EAAgB,OAAA,EAAS,cAAA,IAAkB,UAAA,CAAW;AAAA,GACvD,CAAA;AACH;;;;"}
@@ -1 +1 @@
1
- {"version":3,"file":"record.d.mts","sourceRoot":"","sources":["../../src/record/record.mts"],"names":[],"mappings":"AASA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,IAAI,EACT,KAAK,MAAM,EACX,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAUrB,eAAO,MAAM,MAAM,GACjB,KAAK,CAAC,CAAC,SAAS,YAAY,EAC5B,KAAK,CAAC,EAAE,SAAS,oBAAoB,GAAG,OAAO,SAExC,CAAC,YACE,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,cAAc,EAAE,EAAE,CAAC;CACpB,CAAC,CACH,KACA,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CA0K7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,CAAC,CAAC,SAAS,YAAY,SAChD,CAAC,YACE,OAAO,CAAC,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,KAChD,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAI1B,CAAC;AAML,gBAAgB;AAChB,KAAK,mBAAmB,CAAC,CAAC,SAAS,YAAY,IAC7C,kBAAkB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;AAEhD,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,YAAY,IACxD,0BAA0B,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,KAAK,0BAA0B,CAC7B,CAAC,SAAS,YAAY,EACtB,YAAY,SAAS,MAAM,CAAC,IAE5B,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,IAAI,GACpC,QAAQ,CAAC;SACN,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC9D,CAAC,GACF,MAAM,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,SAAS,IAAI,GACxC,iBAAiB,CACf,QAAQ,CAAC;SAAG,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAAE,CAAC,CACrD,GACD,iBAAiB,CACf,QAAQ,CACN;SAAG,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAAE,GAAG;SAC1C,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC9D,CACF,CACF,CAAC;IAEV,KAAK,gBAAgB,CAAC,CAAC,SAAS,YAAY,IAAI;SAC7C,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC;YAAE,QAAQ,EAAE,IAAI,CAAA;SAAE,CAAC,GAAG,CAAC,GAAG,KAAK;KACtE,CAAC,MAAM,CAAC,CAAC,CAAC;;CACZ"}
1
+ {"version":3,"file":"record.d.mts","sourceRoot":"","sources":["../../src/record/record.mts"],"names":[],"mappings":"AAWA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,aAAa,EAClB,KAAK,MAAM,EAEZ,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,KAAK,oBAAoB,EAEzB,KAAK,IAAI,EACT,KAAK,MAAM,EACX,KAAK,YAAY,EAClB,MAAM,aAAa,CAAC;AAUrB,eAAO,MAAM,MAAM,GACjB,KAAK,CAAC,CAAC,SAAS,YAAY,EAC5B,KAAK,CAAC,EAAE,SAAS,oBAAoB,GAAG,OAAO,SAExC,CAAC,YACE,OAAO,CACf,QAAQ,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;;OAKG;IACH,cAAc,EAAE,EAAE,CAAC;CACpB,CAAC,CACH,KACA,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CA4K7B,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,YAAY,GAAI,KAAK,CAAC,CAAC,SAAS,YAAY,SAChD,CAAC,YACE,OAAO,CAAC,QAAQ,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,KAChD,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAI1B,CAAC;AAML,gBAAgB;AAChB,KAAK,mBAAmB,CAAC,CAAC,SAAS,YAAY,IAC7C,kBAAkB,CAAC,uBAAuB,CAAC,CAAC,CAAC,CAAC;AAEhD,kBAAU,kBAAkB,CAAC;IAC3B,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,YAAY,IACxD,0BAA0B,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC,CAAC;IAErD,KAAK,0BAA0B,CAC7B,CAAC,SAAS,YAAY,EACtB,YAAY,SAAS,MAAM,CAAC,IAE5B,MAAM,CAAC,YAAY,EAAE,KAAK,CAAC,SAAS,IAAI,GACpC,QAAQ,CAAC;SACN,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC9D,CAAC,GACF,MAAM,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,SAAS,IAAI,GACxC,iBAAiB,CACf,QAAQ,CAAC;SAAG,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAAE,CAAC,CACrD,GACD,iBAAiB,CACf,QAAQ,CACN;SAAG,GAAG,IAAI,YAAY,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAAE,GAAG;SAC1C,GAAG,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;KAC9D,CACF,CACF,CAAC;IAEV,KAAK,gBAAgB,CAAC,CAAC,SAAS,YAAY,IAAI;SAC7C,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,QAAQ,CAAC;YAAE,QAAQ,EAAE,IAAI,CAAA;SAAE,CAAC,GAAG,CAAC,GAAG,KAAK;KACtE,CAAC,MAAM,CAAC,CAAC,CAAC;;CACZ"}
@@ -1,4 +1,4 @@
1
- import { memoizeFunction, tp, isRecord, Result, Arr, hasKey } from 'ts-data-forge';
1
+ import { memoizeFunction, tp, isRecord, Result, Arr, hasKey, Obj, Optional } from 'ts-data-forge';
2
2
  import { createAssertFn } from '../utils/create-assert-fn.mjs';
3
3
  import { createCastFn } from '../utils/create-cast-fn.mjs';
4
4
  import { createIsFn } from '../utils/create-is-fn.mjs';
@@ -102,19 +102,17 @@ const record = (shape, options) => {
102
102
  };
103
103
  const prune = (a) => {
104
104
  const rec = a;
105
- return Object.fromEntries(
106
- Object.entries(shape).flatMap(([k, v]) => {
107
- if (v.optional === true) {
108
- if (!hasKey(rec, k)) {
109
- return [];
110
- }
111
- if (rec[k] === void 0) {
112
- return [tp(k, void 0)];
113
- }
105
+ return Obj.filterMap(shape, (v, k) => {
106
+ if (v.optional === true) {
107
+ if (!hasKey(rec, k)) {
108
+ return Optional.none;
114
109
  }
115
- return [tp(k, v.prune(rec[k]))];
116
- })
117
- );
110
+ if (rec[k] === void 0) {
111
+ return Optional.some(void 0);
112
+ }
113
+ }
114
+ return Optional.some(v.prune(rec[k]));
115
+ });
118
116
  };
119
117
  return {
120
118
  typeName: typeNameFilled,
@@ -1 +1 @@
1
- {"version":3,"file":"record.mjs","sources":["../../src/record/record.mts"],"sourcesContent":["import {\n Arr,\n expectType,\n hasKey,\n isRecord,\n memoizeFunction,\n Result,\n tp,\n} from 'ts-data-forge';\nimport {\n type MergeIntersection,\n type StrictExclude,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n type ExcessPropertyOption,\n type RecordTypeInternals,\n type Type,\n type TypeOf,\n type UnknownShape,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n createPrimitiveValidationError,\n prependPathToValidationErrors,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const record = <\n const S extends UnknownShape,\n const EP extends ExcessPropertyOption = 'allow',\n>(\n shape: S,\n options?: Partial<\n Readonly<{\n typeName: string;\n\n /**\n * Controls how excess properties (keys not in shape) are handled.\n *\n * - `'allow'` (default) — accept excess properties\n * - `'reject'` — reject objects with excess properties\n */\n excessProperty: EP;\n }>\n >,\n): Type<RecordTypeFromShape<S>> => {\n type V = RecordTypeFromShape<S>;\n\n const sourceKeys = new Set(Object.keys(shape));\n\n const typeNameFilled: string =\n options?.typeName ??\n `{ ${Object.entries(shape)\n .map(([k, v]) => `${k}: ${v.typeName}`)\n .join(', ')} }`;\n\n const ep: ExcessPropertyOption = options?.excessProperty ?? 'allow';\n\n const getDefaultValue = memoizeFunction(\n (): V =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(shape).map(([key, value]) =>\n tp(key, value.defaultValue),\n ),\n ) as V,\n );\n\n const validate: Type<V>['validate'] = (a) => {\n if (!isRecord(a)) {\n return Result.err([\n createPrimitiveValidationError({\n actualValue: a,\n expectedType: 'record',\n typeName: typeNameFilled,\n details: undefined,\n }),\n ]);\n }\n\n const defaultErrors: readonly ValidationError[] = Arr.generate(\n function* () {\n for (const [k, valueType] of Object.entries(shape)) {\n if (!hasKey(a, k)) {\n if (shape[k]?.optional !== true) {\n yield {\n path: [k],\n actualValue: a,\n typeName: typeNameFilled,\n expectedType: typeNameFilled,\n details: {\n kind: 'missing-key',\n key: k,\n },\n } satisfies ValidationError;\n }\n } else {\n // The case where the key exists in the object\n const v = a[k];\n\n // Skip validation for optional fields with undefined values\n if (v === undefined && valueType.optional === true) {\n continue;\n }\n\n const res = valueType.validate(v);\n\n if (Result.isErr(res)) {\n yield* prependPathToValidationErrors(res.value, k);\n }\n }\n }\n },\n );\n\n if (ep === 'reject') {\n const excessKeys = Object.keys(a).filter((key) => !sourceKeys.has(key));\n\n const excessErrors: readonly ValidationError[] = excessKeys.map(\n (key) =>\n ({\n path: [key],\n actualValue: a[key],\n typeName: typeNameFilled,\n expectedType: typeNameFilled,\n details: {\n kind: 'excess-key',\n key,\n },\n }) satisfies ValidationError,\n );\n\n // Combine all errors\n const allErrors = [...defaultErrors, ...excessErrors] as const;\n\n return Arr.isNonEmpty(allErrors)\n ? Result.err(allErrors)\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Result.ok(a as V);\n }\n\n // ep === 'allow'\n return Arr.isNonEmpty(defaultErrors)\n ? Result.err(defaultErrors)\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Result.ok(a as V);\n };\n\n const fill = (a: unknown): V => {\n if (!isRecord(a)) {\n return getDefaultValue();\n }\n\n // fill always produces shape-only values (strips excess)\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Object.fromEntries(\n Object.entries(shape).map(([k, v]) => {\n if (hasKey(a, k)) {\n const value = a[k];\n\n // For optional fields, if the value is undefined, keep it as undefined\n if (value === undefined && v.optional === true) {\n return tp(k, undefined);\n }\n\n return tp(k, v.fill(value));\n }\n\n return tp(k, v.defaultValue);\n }),\n ) as V;\n };\n\n const prune = (a: V): V => {\n // The input is statically guaranteed to be a record.\n const rec: UnknownRecord = a;\n\n // prune keeps only the value paths represented by the shape;\n // unlike fill, it never fills in missing keys with default values\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Object.fromEntries(\n Object.entries(shape).flatMap(([k, v]) => {\n // Only optional keys can be absent in the input; required keys are\n // statically guaranteed to be present.\n if (v.optional === true) {\n if (!hasKey(rec, k)) {\n return [];\n }\n\n // For optional fields, if the value is undefined, keep it as undefined\n if (rec[k] === undefined) {\n return [tp(k, undefined)];\n }\n }\n\n return [tp(k, v.prune(rec[k]))];\n }),\n ) as V;\n };\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultValue();\n },\n fill,\n prune,\n validate,\n is: createIsFn(validate),\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n shapeStructure: { kind: 'simple', shape } as const,\n excessProperty: ep,\n } satisfies Type<V> & RecordTypeInternals as Type<V>;\n};\n\n/**\n * Creates a strict record type that rejects excess properties.\n * This is an alias for `record(shape, { excessProperty: 'reject' })`.\n */\nexport const strictRecord = <const S extends UnknownShape>(\n shape: S,\n options?: Partial<Readonly<{ typeName: string }>>,\n): Type<RecordTypeFromShape<S>> =>\n record(shape, {\n typeName: options?.typeName,\n excessProperty: 'reject',\n });\n\n// ---------------------------------------------------------------------------\n// RecordTypeValue (internal — computes value type from shape)\n// ---------------------------------------------------------------------------\n\n/** @internal */\ntype RecordTypeFromShape<S extends UnknownShape> =\n TsFortressInternal.RecordTypeFromShapeImpl<S>;\n\nnamespace TsFortressInternal {\n export type RecordTypeFromShapeImpl<S extends UnknownShape> =\n RecordTypeFromShapeImplSub<S, OptionalTypeKeys<S>>;\n\n type RecordTypeFromShapeImplSub<\n S extends UnknownShape,\n OptionalKeys extends keyof S,\n > =\n TypeEq<OptionalKeys, never> extends true\n ? Readonly<{\n [key in StrictExclude<keyof S, OptionalKeys>]: TypeOf<S[key]>;\n }>\n : TypeEq<keyof S, OptionalKeys> extends true\n ? MergeIntersection<\n Readonly<{ [key in OptionalKeys]?: TypeOf<S[key]> }>\n >\n : MergeIntersection<\n Readonly<\n { [key in OptionalKeys]?: TypeOf<S[key]> } & {\n [key in StrictExclude<keyof S, OptionalKeys>]: TypeOf<S[key]>;\n }\n >\n >;\n\n type OptionalTypeKeys<S extends UnknownShape> = {\n [K in keyof S]: S[K] extends Readonly<{ optional: true }> ? K : never;\n }[keyof S];\n}\n\n// --- expectType assertions ---\n\nexpectType<\n RecordTypeFromShape<Readonly<{ a: Type<0>; b: Type<1>; c: Type<2> }>>,\n Readonly<{ a: 0; b: 1; c: 2 }>\n>('=');\n\nexpectType<\n Type<RecordTypeFromShape<Readonly<{ a: Type<0> }>>>,\n Type<Readonly<{ a: 0 }>>\n>('=');\n"],"names":[],"mappings":";;;;;;MA+Ba,MAAA,GAAS,CAIpB,KAAA,EACA,OAAA,KAaiC;AAGjC,EAAA,MAAM,aAAa,IAAI,GAAA,CAAI,MAAA,CAAO,IAAA,CAAK,KAAK,CAAC,CAAA;AAE7C,EAAA,MAAM,cAAA,GACJ,SAAS,QAAA,IACT,CAAA,EAAA,EAAK,OAAO,OAAA,CAAQ,KAAK,CAAA,CACtB,GAAA,CAAI,CAAC,CAAC,GAAG,CAAC,CAAA,KAAM,CAAA,EAAG,CAAC,CAAA,EAAA,EAAK,CAAA,CAAE,QAAQ,CAAA,CAAE,CAAA,CACrC,IAAA,CAAK,IAAI,CAAC,CAAA,EAAA,CAAA;AAEf,EAAA,MAAM,EAAA,GAA2B,SAAS,cAAA,IAAkB,OAAA;AAE5D,EAAA,MAAM,eAAA,GAAkB,eAAA;AAAA,IACtB;AAAA;AAAA,MAEE,MAAA,CAAO,WAAA;AAAA,QACL,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,GAAA;AAAA,UAAI,CAAC,CAAC,GAAA,EAAK,KAAK,MACpC,EAAA,CAAG,GAAA,EAAK,MAAM,YAAY;AAAA;AAC5B;AACF;AAAA,GACJ;AAEA,EAAA,MAAM,QAAA,GAAgC,CAAC,CAAA,KAAM;AAC3C,IAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG;AAChB,MAAA,OAAO,OAAO,GAAA,CAAI;AAAA,QAChB,8BAAA,CAA+B;AAAA,UAC7B,WAAA,EAAa,CAAA;AAAA,UACb,YAAA,EAAc,QAAA;AAAA,UACd,QAAA,EAAU,cAAA;AAAA,UACV,OAAA,EAAS;AAAA,SACV;AAAA,OACF,CAAA;AAAA,IAAA;AAGH,IAAA,MAAM,gBAA4C,GAAA,CAAI,QAAA;AAAA,MACpD,aAAa;AACX,QAAA,KAAA,MAAW,CAAC,CAAA,EAAG,SAAS,KAAK,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,EAAG;AAClD,UAAA,IAAI,CAAC,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAG;AACjB,YAAA,IAAI,KAAA,CAAM,CAAC,CAAA,EAAG,QAAA,KAAa,IAAA,EAAM;AAC/B,cAAA,MAAM;AAAA,gBACJ,IAAA,EAAM,CAAC,CAAC,CAAA;AAAA,gBACR,WAAA,EAAa,CAAA;AAAA,gBACb,QAAA,EAAU,cAAA;AAAA,gBACV,YAAA,EAAc,cAAA;AAAA,gBACd,OAAA,EAAS;AAAA,kBACP,IAAA,EAAM,aAAA;AAAA,kBACN,GAAA,EAAK;AAAA;AACP,eACF;AAAA,YAAA;AACF,UAAA,CACF,MAAO;AAEL,YAAA,MAAM,CAAA,GAAI,EAAE,CAAC,CAAA;AAGb,YAAA,IAAI,CAAA,KAAM,MAAA,IAAa,SAAA,CAAU,QAAA,KAAa,IAAA,EAAM;AAClD,cAAA;AAAA,YAAA;AAGF,YAAA,MAAM,GAAA,GAAM,SAAA,CAAU,QAAA,CAAS,CAAC,CAAA;AAEhC,YAAA,IAAI,MAAA,CAAO,KAAA,CAAM,GAAG,CAAA,EAAG;AACrB,cAAA,OAAO,6BAAA,CAA8B,GAAA,CAAI,KAAA,EAAO,CAAC,CAAA;AAAA,YAAA;AACnD,UAAA;AACF,QAAA;AACF,MAAA;AACF,KACF;AAEA,IAAA,IAAI,OAAO,QAAA,EAAU;AACnB,MAAA,MAAM,UAAA,GAAa,MAAA,CAAO,IAAA,CAAK,CAAC,CAAA,CAAE,MAAA,CAAO,CAAC,GAAA,KAAQ,CAAC,UAAA,CAAW,GAAA,CAAI,GAAG,CAAC,CAAA;AAEtE,MAAA,MAAM,eAA2C,UAAA,CAAW,GAAA;AAAA,QAC1D,CAAC,GAAA,MACE;AAAA,UACC,IAAA,EAAM,CAAC,GAAG,CAAA;AAAA,UACV,WAAA,EAAa,EAAE,GAAG,CAAA;AAAA,UAClB,QAAA,EAAU,cAAA;AAAA,UACV,YAAA,EAAc,cAAA;AAAA,UACd,OAAA,EAAS;AAAA,YACP,IAAA,EAAM,YAAA;AAAA,YACN;AAAA;AACF,SACF;AAAA,OACJ;AAGA,MAAA,MAAM,SAAA,GAAY,CAAC,GAAG,aAAA,EAAe,GAAG,YAAY,CAAA;AAEpD,MAAA,OAAO,IAAI,UAAA,CAAW,SAAS,CAAA,GAC3B,MAAA,CAAO,IAAI,SAAS,CAAA;AAAA;AAAA,QAEpB,MAAA,CAAO,GAAG,CAAM;AAAA,OAAA;AAAA,IAAA;AAItB,IAAA,OAAO,IAAI,UAAA,CAAW,aAAa,CAAA,GAC/B,MAAA,CAAO,IAAI,aAAa,CAAA;AAAA;AAAA,MAExB,MAAA,CAAO,GAAG,CAAM;AAAA,KAAA;AAAA,EAAA,CACtB;AAEA,EAAA,MAAM,IAAA,GAAO,CAAC,CAAA,KAAkB;AAC9B,IAAA,IAAI,CAAC,QAAA,CAAS,CAAC,CAAA,EAAG;AAChB,MAAA,OAAO,eAAA,EAAgB;AAAA,IAAA;AAKzB,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,MACZ,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,IAAI,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AACpC,QAAA,IAAI,MAAA,CAAO,CAAA,EAAG,CAAC,CAAA,EAAG;AAChB,UAAA,MAAM,KAAA,GAAQ,EAAE,CAAC,CAAA;AAGjB,UAAA,IAAI,KAAA,KAAU,MAAA,IAAa,CAAA,CAAE,QAAA,KAAa,IAAA,EAAM;AAC9C,YAAA,OAAO,EAAA,CAAG,GAAG,MAAS,CAAA;AAAA,UAAA;AAGxB,UAAA,OAAO,EAAA,CAAG,CAAA,EAAG,CAAA,CAAE,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,QAAA;AAG5B,QAAA,OAAO,EAAA,CAAG,CAAA,EAAG,CAAA,CAAE,YAAY,CAAA;AAAA,MAAA,CAC5B;AAAA,KACH;AAAA,EAAA,CACF;AAEA,EAAA,MAAM,KAAA,GAAQ,CAAC,CAAA,KAAY;AAEzB,IAAA,MAAM,GAAA,GAAqB,CAAA;AAK3B,IAAA,OAAO,MAAA,CAAO,WAAA;AAAA,MACZ,MAAA,CAAO,QAAQ,KAAK,CAAA,CAAE,QAAQ,CAAC,CAAC,CAAA,EAAG,CAAC,CAAA,KAAM;AAGxC,QAAA,IAAI,CAAA,CAAE,aAAa,IAAA,EAAM;AACvB,UAAA,IAAI,CAAC,MAAA,CAAO,GAAA,EAAK,CAAC,CAAA,EAAG;AACnB,YAAA,OAAO,EAAC;AAAA,UAAA;AAIV,UAAA,IAAI,GAAA,CAAI,CAAC,CAAA,KAAM,MAAA,EAAW;AACxB,YAAA,OAAO,CAAC,EAAA,CAAG,CAAA,EAAG,MAAS,CAAC,CAAA;AAAA,UAAA;AAC1B,QAAA;AAGF,QAAA,OAAO,CAAC,GAAG,CAAA,EAAG,CAAA,CAAE,MAAM,GAAA,CAAI,CAAC,CAAC,CAAC,CAAC,CAAA;AAAA,MAAA,CAC/B;AAAA,KACH;AAAA,EAAA,CACF;AAGA,EAAA,OAAO;AAAA,IACL,QAAA,EAAU,cAAA;AAAA,IACV,IAAI,YAAA,GAAe;AACjB,MAAA,OAAO,eAAA,EAAgB;AAAA,IAAA,CACzB;AAAA,IACA,IAAA;AAAA,IACA,KAAA;AAAA,IACA,QAAA;AAAA,IACA,EAAA,EAAI,WAAW,QAAQ,CAAA;AAAA,IACvB,QAAA,EAAU,eAAe,QAAQ,CAAA;AAAA,IACjC,IAAA,EAAM,aAAa,QAAQ,CAAA;AAAA,IAC3B,cAAA,EAAgB,EAAE,IAAA,EAAM,QAAA,EAAU,KAAA,EAAM;AAAA,IACxC,cAAA,EAAgB;AAAA,GAClB;AACF;AAMO,MAAM,YAAA,GAAe,CAC1B,KAAA,EACA,OAAA,KAEA,OAAO,KAAA,EAAO;AAAA,EACZ,UAAU,OAAA,EAAS,QAAA;AAAA,EACnB,cAAA,EAAgB;AAClB,CAAC;;;;"}
1
+ {"version":3,"file":"record.mjs","sources":["../../src/record/record.mts"],"sourcesContent":["import {\n Arr,\n expectType,\n hasKey,\n isRecord,\n memoizeFunction,\n Obj,\n Optional,\n Result,\n tp,\n} from 'ts-data-forge';\nimport {\n type MergeIntersection,\n type StrictExclude,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n type ExcessPropertyOption,\n type RecordTypeInternals,\n type Type,\n type TypeOf,\n type UnknownShape,\n} from '../type.mjs';\nimport {\n createAssertFn,\n createCastFn,\n createIsFn,\n createPrimitiveValidationError,\n prependPathToValidationErrors,\n type ValidationError,\n} from '../utils/index.mjs';\n\nexport const record = <\n const S extends UnknownShape,\n const EP extends ExcessPropertyOption = 'allow',\n>(\n shape: S,\n options?: Partial<\n Readonly<{\n typeName: string;\n\n /**\n * Controls how excess properties (keys not in shape) are handled.\n *\n * - `'allow'` (default) — accept excess properties\n * - `'reject'` — reject objects with excess properties\n */\n excessProperty: EP;\n }>\n >,\n): Type<RecordTypeFromShape<S>> => {\n type V = RecordTypeFromShape<S>;\n\n // Annotated rather than inferred: the strict standard library types\n // `Object.keys` as the record's own key union, which would make `has` reject\n // the plain `string` keys read back off the value being validated. The\n // membership test is the point here, so the wider element type is correct.\n const sourceKeys: ReadonlySet<string> = new Set(Object.keys(shape));\n\n const typeNameFilled: string =\n options?.typeName ??\n `{ ${Object.entries(shape)\n .map(([k, v]) => `${k}: ${v.typeName}`)\n .join(', ')} }`;\n\n const ep: ExcessPropertyOption = options?.excessProperty ?? 'allow';\n\n const getDefaultValue = memoizeFunction(\n (): V =>\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Object.fromEntries(\n Object.entries(shape).map(([key, value]) =>\n tp(key, value.defaultValue),\n ),\n ) as V,\n );\n\n const validate: Type<V>['validate'] = (a) => {\n if (!isRecord(a)) {\n return Result.err([\n createPrimitiveValidationError({\n actualValue: a,\n expectedType: 'record',\n typeName: typeNameFilled,\n details: undefined,\n }),\n ]);\n }\n\n const defaultErrors: readonly ValidationError[] = Arr.generate(\n function* () {\n for (const [k, valueType] of Object.entries(shape)) {\n if (!hasKey(a, k)) {\n if (shape[k]?.optional !== true) {\n yield {\n path: [k],\n actualValue: a,\n typeName: typeNameFilled,\n expectedType: typeNameFilled,\n details: {\n kind: 'missing-key',\n key: k,\n },\n } satisfies ValidationError;\n }\n } else {\n // The case where the key exists in the object\n const v = a[k];\n\n // Skip validation for optional fields with undefined values\n if (v === undefined && valueType.optional === true) {\n continue;\n }\n\n const res = valueType.validate(v);\n\n if (Result.isErr(res)) {\n yield* prependPathToValidationErrors(res.value, k);\n }\n }\n }\n },\n );\n\n if (ep === 'reject') {\n const excessKeys = Object.keys(a).filter((key) => !sourceKeys.has(key));\n\n const excessErrors: readonly ValidationError[] = excessKeys.map(\n (key) =>\n ({\n path: [key],\n actualValue: a[key],\n typeName: typeNameFilled,\n expectedType: typeNameFilled,\n details: {\n kind: 'excess-key',\n key,\n },\n }) satisfies ValidationError,\n );\n\n // Combine all errors\n const allErrors = [...defaultErrors, ...excessErrors] as const;\n\n return Arr.isNonEmpty(allErrors)\n ? Result.err(allErrors)\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Result.ok(a as V);\n }\n\n // ep === 'allow'\n return Arr.isNonEmpty(defaultErrors)\n ? Result.err(defaultErrors)\n : // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n Result.ok(a as V);\n };\n\n const fill = (a: unknown): V => {\n if (!isRecord(a)) {\n return getDefaultValue();\n }\n\n // fill always produces shape-only values (strips excess)\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Object.fromEntries(\n Object.entries(shape).map(([k, v]) => {\n if (hasKey(a, k)) {\n const value = a[k];\n\n // For optional fields, if the value is undefined, keep it as undefined\n if (value === undefined && v.optional === true) {\n return tp(k, undefined);\n }\n\n return tp(k, v.fill(value));\n }\n\n return tp(k, v.defaultValue);\n }),\n ) as V;\n };\n\n const prune = (a: V): V => {\n // The input is statically guaranteed to be a record.\n const rec: UnknownRecord = a;\n\n // prune keeps only the value paths represented by the shape;\n // unlike fill, it never fills in missing keys with default values\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return Obj.filterMap(shape, (v, k) => {\n // Only optional keys can be absent in the input; required keys are\n // statically guaranteed to be present.\n if (v.optional === true) {\n if (!hasKey(rec, k)) {\n return Optional.none;\n }\n\n // For optional fields, if the value is undefined, keep it as undefined\n if (rec[k] === undefined) {\n return Optional.some(undefined);\n }\n }\n\n return Optional.some(v.prune(rec[k]));\n }) as V;\n };\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return {\n typeName: typeNameFilled,\n get defaultValue() {\n return getDefaultValue();\n },\n fill,\n prune,\n validate,\n is: createIsFn(validate),\n assertIs: createAssertFn(validate),\n cast: createCastFn(validate),\n shapeStructure: { kind: 'simple', shape } as const,\n excessProperty: ep,\n } satisfies Type<V> & RecordTypeInternals as Type<V>;\n};\n\n/**\n * Creates a strict record type that rejects excess properties.\n * This is an alias for `record(shape, { excessProperty: 'reject' })`.\n */\nexport const strictRecord = <const S extends UnknownShape>(\n shape: S,\n options?: Partial<Readonly<{ typeName: string }>>,\n): Type<RecordTypeFromShape<S>> =>\n record(shape, {\n typeName: options?.typeName,\n excessProperty: 'reject',\n });\n\n// ---------------------------------------------------------------------------\n// RecordTypeValue (internal — computes value type from shape)\n// ---------------------------------------------------------------------------\n\n/** @internal */\ntype RecordTypeFromShape<S extends UnknownShape> =\n TsFortressInternal.RecordTypeFromShapeImpl<S>;\n\nnamespace TsFortressInternal {\n export type RecordTypeFromShapeImpl<S extends UnknownShape> =\n RecordTypeFromShapeImplSub<S, OptionalTypeKeys<S>>;\n\n type RecordTypeFromShapeImplSub<\n S extends UnknownShape,\n OptionalKeys extends keyof S,\n > =\n TypeEq<OptionalKeys, never> extends true\n ? Readonly<{\n [key in StrictExclude<keyof S, OptionalKeys>]: TypeOf<S[key]>;\n }>\n : TypeEq<keyof S, OptionalKeys> extends true\n ? MergeIntersection<\n Readonly<{ [key in OptionalKeys]?: TypeOf<S[key]> }>\n >\n : MergeIntersection<\n Readonly<\n { [key in OptionalKeys]?: TypeOf<S[key]> } & {\n [key in StrictExclude<keyof S, OptionalKeys>]: TypeOf<S[key]>;\n }\n >\n >;\n\n type OptionalTypeKeys<S extends UnknownShape> = {\n [K in keyof S]: S[K] extends Readonly<{ optional: true }> ? K : never;\n }[keyof S];\n}\n\n// --- expectType assertions ---\n\nexpectType<\n RecordTypeFromShape<Readonly<{ a: Type<0>; b: Type<1>; c: Type<2> }>>,\n Readonly<{ a: 0; b: 1; c: 2 }>\n>('=');\n\nexpectType<\n Type<RecordTypeFromShape<Readonly<{ a: Type<0> }>>>,\n Type<Readonly<{ a: 0 }>>\n>('=');\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"required.d.mts","sourceRoot":"","sources":["../../src/record/required.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,IAAI,EAGV,MAAM,aAAa,CAAC;AAKrB;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,cAElD,IAAI,CAAC,CAAC,CAAC,YACT,OAAO,CACf,QAAQ,CAAC;IACP,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC,CACH,KACA,YAAY,CAAC,CAAC,EAAE,gBAAgB,CAoClC,CAAC;AAEF,KAAK,YAAY,CACf,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,IACtD,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE7C,uCAAuC;AACvC,KAAK,aAAa,CAChB,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,IAEpE,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,SAAS,IAAI,GAC5C,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GACrB,iBAAiB,CAAC,CAAC,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"required.d.mts","sourceRoot":"","sources":["../../src/record/required.mts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,KAAK,iBAAiB,EACtB,KAAK,MAAM,EACX,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EAIL,KAAK,oBAAoB,EACzB,KAAK,IAAI,EAGV,MAAM,aAAa,CAAC;AAKrB;;;GAGG;AACH,eAAO,MAAM,QAAQ,GACnB,KAAK,CAAC,CAAC,SAAS,aAAa,EAC7B,KAAK,CAAC,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,cAElD,IAAI,CAAC,CAAC,CAAC,YACT,OAAO,CACf,QAAQ,CAAC;IACP,gBAAgB,EAAE,gBAAgB,CAAC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,oBAAoB,CAAC;CACtC,CAAC,CACH,KACA,YAAY,CAAC,CAAC,EAAE,gBAAgB,CAkClC,CAAC;AAEF,KAAK,YAAY,CACf,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,IACtD,IAAI,CAAC,aAAa,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAE7C,uCAAuC;AACvC,KAAK,aAAa,CAChB,CAAC,SAAS,aAAa,EACvB,gBAAgB,SAAS,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,SAAS,IAEpE,MAAM,CAAC,gBAAgB,EAAE,SAAS,CAAC,SAAS,IAAI,GAC5C,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,GACrB,iBAAiB,CAAC,CAAC,EAAE,YAAY,CAAC,gBAAgB,CAAC,CAAC,CAAC"}
@@ -1,4 +1,4 @@
1
- import 'ts-data-forge';
1
+ import { Obj } from 'ts-data-forge';
2
2
  import { hasRecordInternals, flattenShapeStructure } from '../type.mjs';
3
3
  import '@sindresorhus/is';
4
4
  import { toUnionKeyString } from '../utils/to-union-string.mjs';
@@ -21,10 +21,9 @@ const required = (recordType, options) => {
21
21
  const keysToBeRequired = new Set(
22
22
  options?.keysToBeRequired ?? Object.keys(shape)
23
23
  );
24
- const requiredShape = Object.fromEntries(
25
- Object.entries(shape).map(
26
- ([k, v]) => [k, keysToBeRequired.has(k) ? makeRequired(v) : v]
27
- )
24
+ const requiredShape = Obj.map(
25
+ shape,
26
+ (v, k) => keysToBeRequired.has(k) ? makeRequired(v) : v
28
27
  );
29
28
  return record(requiredShape, {
30
29
  typeName: typeNameFilled,
@@ -1 +1 @@
1
- {"version":3,"file":"required.mjs","sources":["../../src/record/required.mts"],"sourcesContent":["import { expectType } from 'ts-data-forge';\nimport {\n type ArrayElement,\n type NonEmptyTuple,\n type PartiallyRequired,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n flattenShapeStructure,\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n type UnknownShape,\n} from '../type.mjs';\nimport { toUnionKeyString } from '../utils/index.mjs';\nimport { isOptionalProperty, type RequiredPropertyType } from './optional.mjs';\nimport { record } from './record.mjs';\n\n/**\n * Creates a Required type. If keysToBeRequired is set, only those keys are\n * made required, otherwise, all properties are made required.\n */\nexport const required = <\n const R extends UnknownRecord,\n const KeysToBeRequired extends NonEmptyTuple<keyof R & string>,\n>(\n recordType: Type<R>,\n options?: Partial<\n Readonly<{\n keysToBeRequired: KeysToBeRequired;\n typeName: string;\n excessProperty: ExcessPropertyOption;\n }>\n >,\n): RequiredType<R, KeysToBeRequired> => {\n if (!hasRecordInternals(recordType)) {\n throw new Error(\n `Expected a record type but received: ${recordType.typeName}`,\n );\n }\n\n const shape = flattenShapeStructure(recordType.shapeStructure);\n\n if (shape === undefined) {\n throw new Error(\n `required() requires a simple or intersection record type, but received a union type`,\n );\n }\n\n const typeNameFilled: string =\n options?.typeName ??\n (options?.keysToBeRequired === undefined\n ? `Required<${recordType.typeName}>`\n : `PartiallyRequired<${recordType.typeName}, ${toUnionKeyString(options.keysToBeRequired)}>`);\n\n const keysToBeRequired: ReadonlySet<string> = new Set(\n options?.keysToBeRequired ?? Object.keys(shape),\n );\n\n const requiredShape = Object.fromEntries(\n Object.entries(shape).map(\n ([k, v]) => [k, keysToBeRequired.has(k) ? makeRequired(v) : v] as const,\n ),\n ) satisfies UnknownShape;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return record(requiredShape, {\n typeName: typeNameFilled,\n excessProperty: options?.excessProperty ?? recordType.excessProperty,\n }) as unknown as Type<RequiredValue<R, KeysToBeRequired>>;\n};\n\ntype RequiredType<\n R extends UnknownRecord,\n KeysToBeRequired extends NonEmptyTuple<keyof R & string>,\n> = Type<RequiredValue<R, KeysToBeRequired>>;\n\n/** Compute the required value type. */\ntype RequiredValue<\n R extends UnknownRecord,\n KeysToBeRequired extends NonEmptyTuple<keyof R & string> | undefined,\n> =\n TypeEq<KeysToBeRequired, undefined> extends true\n ? Readonly<Required<R>>\n : PartiallyRequired<R, ArrayElement<KeysToBeRequired>>;\n\n/**\n * Makes an optional property required by removing the optional flag.\n */\nconst makeRequired = <T extends AnyType>(t: T): RequiredPropertyType<T> => {\n if (!isOptionalProperty(t)) {\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return t as RequiredPropertyType<T>;\n }\n\n const { optional: _, ...rest } = t;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return rest as RequiredPropertyType<T>;\n};\n\n// --- expectType assertions ---\n\n{\n type Base = ReturnType<\n typeof record<\n Readonly<{ a: Type<0>; b: Type<1 | undefined>; c: Type<2 | undefined> }>\n >\n >;\n\n // required with no keys makes all properties required\n expectType<\n TypeOf<ReturnType<typeof required<TypeOf<Base>, readonly ['a', 'b', 'c']>>>,\n Readonly<Required<Readonly<{ a: 0; b: 1 | undefined; c: 2 | undefined }>>>\n >('=');\n}\n"],"names":[],"mappings":";;;;;;;MAyBa,QAAA,GAAW,CAItB,UAAA,EACA,OAAA,KAOsC;AACtC,EAAA,IAAI,CAAC,kBAAA,CAAmB,UAAU,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qCAAA,EAAwC,WAAW,QAAQ,CAAA;AAAA,KAC7D;AAAA,EAAA;AAGF,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,UAAA,CAAW,cAAc,CAAA;AAE7D,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,mFAAA;AAAA,KACF;AAAA,EAAA;AAGF,EAAA,MAAM,iBACJ,OAAA,EAAS,QAAA,KACR,OAAA,EAAS,gBAAA,KAAqB,SAC3B,CAAA,SAAA,EAAY,UAAA,CAAW,QAAQ,CAAA,CAAA,CAAA,GAC/B,qBAAqB,UAAA,CAAW,QAAQ,KAAK,gBAAA,CAAiB,OAAA,CAAQ,gBAAgB,CAAC,CAAA,CAAA,CAAA,CAAA;AAE7F,EAAA,MAAM,mBAAwC,IAAI,GAAA;AAAA,IAChD,OAAA,EAAS,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAK,KAAK;AAAA,GAChD;AAEA,EAAA,MAAM,gBAAgB,MAAA,CAAO,WAAA;AAAA,IAC3B,MAAA,CAAO,OAAA,CAAQ,KAAK,CAAA,CAAE,GAAA;AAAA,MACpB,CAAC,CAAC,CAAA,EAAG,CAAC,MAAM,CAAC,CAAA,EAAG,gBAAA,CAAiB,GAAA,CAAI,CAAC,CAAA,GAAI,YAAA,CAAa,CAAC,IAAI,CAAC;AAAA;AAC/D,GACF;AAGA,EAAA,OAAO,OAAO,aAAA,EAAe;AAAA,IAC3B,QAAA,EAAU,cAAA;AAAA,IACV,cAAA,EAAgB,OAAA,EAAS,cAAA,IAAkB,UAAA,CAAW;AAAA,GACvD,CAAA;AACH;AAmBA,MAAM,YAAA,GAAe,CAAoB,CAAA,KAAkC;AACzE,EAAA,IAAI,CAAC,kBAAA,CAAmB,CAAC,CAAA,EAAG;AAE1B,IAAA,OAAO,CAAA;AAAA,EAAA;AAGT,EAAA,MAAM,EAAE,QAAA,EAAU,CAAA,EAAG,GAAG,MAAK,GAAI,CAAA;AAGjC,EAAA,OAAO,IAAA;AACT,CAAA;;;;"}
1
+ {"version":3,"file":"required.mjs","sources":["../../src/record/required.mts"],"sourcesContent":["import { Obj, expectType } from 'ts-data-forge';\nimport {\n type ArrayElement,\n type NonEmptyTuple,\n type PartiallyRequired,\n type TypeEq,\n type UnknownRecord,\n} from 'ts-type-forge';\nimport {\n flattenShapeStructure,\n hasRecordInternals,\n type AnyType,\n type ExcessPropertyOption,\n type Type,\n type TypeOf,\n type UnknownShape,\n} from '../type.mjs';\nimport { toUnionKeyString } from '../utils/index.mjs';\nimport { isOptionalProperty, type RequiredPropertyType } from './optional.mjs';\nimport { record } from './record.mjs';\n\n/**\n * Creates a Required type. If keysToBeRequired is set, only those keys are\n * made required, otherwise, all properties are made required.\n */\nexport const required = <\n const R extends UnknownRecord,\n const KeysToBeRequired extends NonEmptyTuple<keyof R & string>,\n>(\n recordType: Type<R>,\n options?: Partial<\n Readonly<{\n keysToBeRequired: KeysToBeRequired;\n typeName: string;\n excessProperty: ExcessPropertyOption;\n }>\n >,\n): RequiredType<R, KeysToBeRequired> => {\n if (!hasRecordInternals(recordType)) {\n throw new Error(\n `Expected a record type but received: ${recordType.typeName}`,\n );\n }\n\n const shape = flattenShapeStructure(recordType.shapeStructure);\n\n if (shape === undefined) {\n throw new Error(\n `required() requires a simple or intersection record type, but received a union type`,\n );\n }\n\n const typeNameFilled: string =\n options?.typeName ??\n (options?.keysToBeRequired === undefined\n ? `Required<${recordType.typeName}>`\n : `PartiallyRequired<${recordType.typeName}, ${toUnionKeyString(options.keysToBeRequired)}>`);\n\n const keysToBeRequired: ReadonlySet<string> = new Set(\n options?.keysToBeRequired ?? Object.keys(shape),\n );\n\n const requiredShape = Obj.map(shape, (v, k) =>\n keysToBeRequired.has(k) ? makeRequired(v) : v,\n ) satisfies UnknownShape;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return record(requiredShape, {\n typeName: typeNameFilled,\n excessProperty: options?.excessProperty ?? recordType.excessProperty,\n }) as unknown as Type<RequiredValue<R, KeysToBeRequired>>;\n};\n\ntype RequiredType<\n R extends UnknownRecord,\n KeysToBeRequired extends NonEmptyTuple<keyof R & string>,\n> = Type<RequiredValue<R, KeysToBeRequired>>;\n\n/** Compute the required value type. */\ntype RequiredValue<\n R extends UnknownRecord,\n KeysToBeRequired extends NonEmptyTuple<keyof R & string> | undefined,\n> =\n TypeEq<KeysToBeRequired, undefined> extends true\n ? Readonly<Required<R>>\n : PartiallyRequired<R, ArrayElement<KeysToBeRequired>>;\n\n/**\n * Makes an optional property required by removing the optional flag.\n */\nconst makeRequired = <T extends AnyType>(t: T): RequiredPropertyType<T> => {\n if (!isOptionalProperty(t)) {\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return t as RequiredPropertyType<T>;\n }\n\n const { optional: _, ...rest } = t;\n\n // eslint-disable-next-line total-functions/no-unsafe-type-assertion\n return rest as RequiredPropertyType<T>;\n};\n\n// --- expectType assertions ---\n\n{\n type Base = ReturnType<\n typeof record<\n Readonly<{ a: Type<0>; b: Type<1 | undefined>; c: Type<2 | undefined> }>\n >\n >;\n\n // required with no keys makes all properties required\n expectType<\n TypeOf<ReturnType<typeof required<TypeOf<Base>, readonly ['a', 'b', 'c']>>>,\n Readonly<Required<Readonly<{ a: 0; b: 1 | undefined; c: 2 | undefined }>>>\n >('=');\n}\n"],"names":[],"mappings":";;;;;;;MAyBa,QAAA,GAAW,CAItB,UAAA,EACA,OAAA,KAOsC;AACtC,EAAA,IAAI,CAAC,kBAAA,CAAmB,UAAU,CAAA,EAAG;AACnC,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,qCAAA,EAAwC,WAAW,QAAQ,CAAA;AAAA,KAC7D;AAAA,EAAA;AAGF,EAAA,MAAM,KAAA,GAAQ,qBAAA,CAAsB,UAAA,CAAW,cAAc,CAAA;AAE7D,EAAA,IAAI,UAAU,MAAA,EAAW;AACvB,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,CAAA,mFAAA;AAAA,KACF;AAAA,EAAA;AAGF,EAAA,MAAM,iBACJ,OAAA,EAAS,QAAA,KACR,OAAA,EAAS,gBAAA,KAAqB,SAC3B,CAAA,SAAA,EAAY,UAAA,CAAW,QAAQ,CAAA,CAAA,CAAA,GAC/B,qBAAqB,UAAA,CAAW,QAAQ,KAAK,gBAAA,CAAiB,OAAA,CAAQ,gBAAgB,CAAC,CAAA,CAAA,CAAA,CAAA;AAE7F,EAAA,MAAM,mBAAwC,IAAI,GAAA;AAAA,IAChD,OAAA,EAAS,gBAAA,IAAoB,MAAA,CAAO,IAAA,CAAK,KAAK;AAAA,GAChD;AAEA,EAAA,MAAM,gBAAgB,GAAA,CAAI,GAAA;AAAA,IAAI,KAAA;AAAA,IAAO,CAAC,GAAG,CAAA,KACvC,gBAAA,CAAiB,IAAI,CAAC,CAAA,GAAI,YAAA,CAAa,CAAC,CAAA,GAAI;AAAA,GAC9C;AAGA,EAAA,OAAO,OAAO,aAAA,EAAe;AAAA,IAC3B,QAAA,EAAU,cAAA;AAAA,IACV,cAAA,EAAgB,OAAA,EAAS,cAAA,IAAkB,UAAA,CAAW;AAAA,GACvD,CAAA;AACH;AAmBA,MAAM,YAAA,GAAe,CAAoB,CAAA,KAAkC;AACzE,EAAA,IAAI,CAAC,kBAAA,CAAmB,CAAC,CAAA,EAAG;AAE1B,IAAA,OAAO,CAAA;AAAA,EAAA;AAGT,EAAA,MAAM,EAAE,QAAA,EAAU,CAAA,EAAG,GAAG,MAAK,GAAI,CAAA;AAGjC,EAAA,OAAO,IAAA;AACT,CAAA;;;;"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-fortress",
3
- "version": "12.0.2",
3
+ "version": "12.0.4",
4
4
  "private": false,
5
5
  "keywords": [
6
6
  "typescript"
@@ -36,12 +36,15 @@
36
36
  ],
37
37
  "dependencies": {
38
38
  "@sindresorhus/is": "8.1.0",
39
- "ts-data-forge": "~14.3.0",
40
- "ts-type-forge": "~9.2.1"
39
+ "ts-data-forge": "~14.5.0",
40
+ "ts-type-forge": "~9.2.2"
41
41
  },
42
42
  "devDependencies": {
43
- "@vitest/browser-playwright": "4.1.10",
44
- "@vitest/ui": "4.1.10",
43
+ "@vitest/browser-playwright": "4.1.11",
44
+ "@vitest/ui": "4.1.11",
45
+ "eslint-config-typed": "5.10.0",
46
+ "eslint-plugin-ts-data-forge": "0.5.1",
47
+ "eslint-plugin-ts-type-forge": "0.7.1",
45
48
  "fp-ts": "2.16.11",
46
49
  "io-ts": "2.2.22",
47
50
  "playwright": "1.62.1",
@@ -49,14 +52,11 @@
49
52
  "prettier-plugin-organize-imports": "4.3.0",
50
53
  "prettier-plugin-packagejson": "3.0.2",
51
54
  "rollup": "4.62.4",
55
+ "ts-repo-utils": "10.3.2",
52
56
  "typedoc": "0.28.20",
53
57
  "typedoc-github-theme": "0.4.0",
54
58
  "vite": "8.2.1",
55
- "zod": "4.4.3",
56
- "eslint-config-typed": "5.9.2",
57
- "eslint-plugin-ts-data-forge": "0.4.7",
58
- "eslint-plugin-ts-type-forge": "0.6.5",
59
- "ts-repo-utils": "10.2.0"
59
+ "zod": "4.4.3"
60
60
  },
61
61
  "engines": {
62
62
  "node": ">=22.22.2",
@@ -1,4 +1,4 @@
1
- import { Arr, expectType, hasKey, isRecord, Result, tp } from 'ts-data-forge';
1
+ import { Arr, expectType, hasKey, isRecord, Obj, Result } from 'ts-data-forge';
2
2
  import { type Intersection, type NonEmptyTuple } from 'ts-type-forge';
3
3
  import {
4
4
  hasRecordInternals,
@@ -118,15 +118,11 @@ export const intersection = <const Types extends NonEmptyTuple<AnyType>>(
118
118
  */
119
119
  const mergePruned = (x: unknown, y: unknown): unknown => {
120
120
  if (isRecord(x) && isRecord(y)) {
121
- const xMergedWithY = Object.fromEntries(
122
- Object.entries(x).map(([k, xv]) =>
123
- tp(k, hasKey(y, k) ? mergePruned(xv, y[k]) : xv),
124
- ),
121
+ const xMergedWithY = Obj.map(x, (xv, k) =>
122
+ hasKey(y, k) ? mergePruned(xv, y[k]) : xv,
125
123
  );
126
124
 
127
- const yOnly = Object.fromEntries(
128
- Object.entries(y).filter(([k]) => !hasKey(x, k)),
129
- );
125
+ const yOnly = Obj.filter(y, (_yv, k) => !hasKey(x, k));
130
126
 
131
127
  return { ...xMergedWithY, ...yOnly };
132
128
  }
@@ -201,27 +201,27 @@ const createConstraintsPredicate =
201
201
  }
202
202
 
203
203
  if (gt !== undefined && !(value > gt)) {
204
- return Result.err({ constraint: 'gt', value: String(gt) } as const);
204
+ return Result.err({ constraint: 'gt', value: gt.toString() } as const);
205
205
  }
206
206
 
207
207
  if (gte !== undefined && !(value >= gte)) {
208
- return Result.err({ constraint: 'gte', value: String(gte) } as const);
208
+ return Result.err({ constraint: 'gte', value: gte.toString() } as const);
209
209
  }
210
210
 
211
211
  if (min !== undefined && !(value >= min)) {
212
- return Result.err({ constraint: 'min', value: String(min) } as const);
212
+ return Result.err({ constraint: 'min', value: min.toString() } as const);
213
213
  }
214
214
 
215
215
  if (lt !== undefined && !(value < lt)) {
216
- return Result.err({ constraint: 'lt', value: String(lt) } as const);
216
+ return Result.err({ constraint: 'lt', value: lt.toString() } as const);
217
217
  }
218
218
 
219
219
  if (lte !== undefined && !(value <= lte)) {
220
- return Result.err({ constraint: 'lte', value: String(lte) } as const);
220
+ return Result.err({ constraint: 'lte', value: lte.toString() } as const);
221
221
  }
222
222
 
223
223
  if (max !== undefined && !(value <= max)) {
224
- return Result.err({ constraint: 'max', value: String(max) } as const);
224
+ return Result.err({ constraint: 'max', value: max.toString() } as const);
225
225
  }
226
226
 
227
227
  // `value % 0n` throws a RangeError, so the zero divisor is handled
@@ -231,13 +231,13 @@ const createConstraintsPredicate =
231
231
  if (value !== 0n) {
232
232
  return Result.err({
233
233
  constraint: 'multipleOf',
234
- value: String(multipleOf),
234
+ value: multipleOf.toString(),
235
235
  } as const);
236
236
  }
237
237
  } else if (value % multipleOf !== 0n) {
238
238
  return Result.err({
239
239
  constraint: 'multipleOf',
240
- value: String(multipleOf),
240
+ value: multipleOf.toString(),
241
241
  } as const);
242
242
  }
243
243
  }
@@ -247,11 +247,14 @@ const createConstraintsPredicate =
247
247
  if (value !== 0n) {
248
248
  return Result.err({
249
249
  constraint: 'step',
250
- value: String(step),
250
+ value: step.toString(),
251
251
  } as const);
252
252
  }
253
253
  } else if (value % step !== 0n) {
254
- return Result.err({ constraint: 'step', value: String(step) } as const);
254
+ return Result.err({
255
+ constraint: 'step',
256
+ value: step.toString(),
257
+ } as const);
255
258
  }
256
259
  }
257
260
 
@@ -373,27 +373,27 @@ const createConstraintsPredicate =
373
373
  }
374
374
 
375
375
  if (gt !== undefined && !(value > gt)) {
376
- return Result.err({ constraint: 'gt', value: String(gt) } as const);
376
+ return Result.err({ constraint: 'gt', value: gt.toString() } as const);
377
377
  }
378
378
 
379
379
  if (gte !== undefined && !(value >= gte)) {
380
- return Result.err({ constraint: 'gte', value: String(gte) } as const);
380
+ return Result.err({ constraint: 'gte', value: gte.toString() } as const);
381
381
  }
382
382
 
383
383
  if (min !== undefined && !(value >= min)) {
384
- return Result.err({ constraint: 'min', value: String(min) } as const);
384
+ return Result.err({ constraint: 'min', value: min.toString() } as const);
385
385
  }
386
386
 
387
387
  if (lt !== undefined && !(value < lt)) {
388
- return Result.err({ constraint: 'lt', value: String(lt) } as const);
388
+ return Result.err({ constraint: 'lt', value: lt.toString() } as const);
389
389
  }
390
390
 
391
391
  if (lte !== undefined && !(value <= lte)) {
392
- return Result.err({ constraint: 'lte', value: String(lte) } as const);
392
+ return Result.err({ constraint: 'lte', value: lte.toString() } as const);
393
393
  }
394
394
 
395
395
  if (max !== undefined && !(value <= max)) {
396
- return Result.err({ constraint: 'max', value: String(max) } as const);
396
+ return Result.err({ constraint: 'max', value: max.toString() } as const);
397
397
  }
398
398
 
399
399
  // `value % 0` throws a RangeError, so the zero divisor is handled
@@ -403,13 +403,13 @@ const createConstraintsPredicate =
403
403
  if (value !== 0) {
404
404
  return Result.err({
405
405
  constraint: 'multipleOf',
406
- value: String(multipleOf),
406
+ value: multipleOf.toString(),
407
407
  } as const);
408
408
  }
409
409
  } else if (value % multipleOf !== 0) {
410
410
  return Result.err({
411
411
  constraint: 'multipleOf',
412
- value: String(multipleOf),
412
+ value: multipleOf.toString(),
413
413
  } as const);
414
414
  }
415
415
  }
@@ -419,11 +419,14 @@ const createConstraintsPredicate =
419
419
  if (value !== 0) {
420
420
  return Result.err({
421
421
  constraint: 'step',
422
- value: String(step),
422
+ value: step.toString(),
423
423
  } as const);
424
424
  }
425
425
  } else if (value % step !== 0) {
426
- return Result.err({ constraint: 'step', value: String(step) } as const);
426
+ return Result.err({
427
+ constraint: 'step',
428
+ value: step.toString(),
429
+ } as const);
427
430
  }
428
431
  }
429
432
 
@@ -1,4 +1,4 @@
1
- import { Arr, isRecord, Result, tp } from 'ts-data-forge';
1
+ import { Arr, isRecord, Obj, Optional, Result } from 'ts-data-forge';
2
2
  import { type ReadonlyRecord } from 'ts-type-forge';
3
3
  import { type AnyType, type Type, type TypeOf } from '../type.mjs';
4
4
  import {
@@ -98,20 +98,14 @@ export const keyValueRecord = <K extends Type<string>, V extends AnyType>(
98
98
  const fill: Type<T>['fill'] = (a) =>
99
99
  isRecord(a)
100
100
  ? // eslint-disable-next-line total-functions/no-unsafe-type-assertion
101
- (Object.fromEntries(
102
- Object.entries(a).filter(
103
- ([k, v]) => keyType.is(k) && valueType.is(v),
104
- ),
105
- ) as T)
101
+ (Obj.filter(a, (v, k) => keyType.is(k) && valueType.is(v)) as T)
106
102
  : defaultValue;
107
103
 
108
104
  // Keys not matching keyType are excess paths; values are pruned recursively.
109
105
  const prune = (a: T): T =>
110
106
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
111
- Object.fromEntries(
112
- Object.entries(a)
113
- .filter(([k]) => keyType.is(k))
114
- .map(([k, v]) => tp(k, valueType.prune(v))),
107
+ Obj.filterMap(a, (v, k) =>
108
+ keyType.is(k) ? Optional.some(valueType.prune(v)) : Optional.none,
115
109
  ) as T;
116
110
 
117
111
  return {
@@ -1,5 +1,6 @@
1
1
  import { expectType, Result } from 'ts-data-forge';
2
2
  import { type ReadonlyRecord, type UnknownRecord } from 'ts-type-forge';
3
+ import { literal } from '../other-types/index.mjs';
3
4
  import { number, string } from '../primitives/index.mjs';
4
5
  import { type TypeOf } from '../type.mjs';
5
6
  import {
@@ -226,4 +227,19 @@ describe(keyValueRecord, () => {
226
227
  assert.isFalse(strNumRecord.is(x));
227
228
  });
228
229
  });
230
+
231
+ describe('prune', () => {
232
+ test('keeps every entry when all keys match the key type', () => {
233
+ assert.deepStrictEqual(strNumRecord.prune({ year: 2000, month: 12 }), {
234
+ year: 2000,
235
+ month: 12,
236
+ });
237
+ });
238
+
239
+ test('drops the entries whose key does not match the key type', () => {
240
+ const onlyA = keyValueRecord(literal('a'), number());
241
+
242
+ assert.deepStrictEqual(onlyA.prune({ a: 1, b: 2 }), { a: 1 });
243
+ });
244
+ });
229
245
  });
@@ -1,4 +1,4 @@
1
- import { expectType } from 'ts-data-forge';
1
+ import { Obj, expectType } from 'ts-data-forge';
2
2
  import {
3
3
  type ArrayElement,
4
4
  type NonEmptyTuple,
@@ -59,10 +59,8 @@ export const partial = <
59
59
  options?.keysToBeOptional ?? Object.keys(shape),
60
60
  );
61
61
 
62
- const partialShape = Object.fromEntries(
63
- Object.entries(shape).map(
64
- ([k, v]) => [k, keysToBeOptional.has(k) ? optional(v) : v] as const,
65
- ),
62
+ const partialShape = Obj.map(shape, (v, k) =>
63
+ keysToBeOptional.has(k) ? optional(v) : v,
66
64
  ) satisfies UnknownShape;
67
65
 
68
66
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -4,6 +4,8 @@ import {
4
4
  hasKey,
5
5
  isRecord,
6
6
  memoizeFunction,
7
+ Obj,
8
+ Optional,
7
9
  Result,
8
10
  tp,
9
11
  } from 'ts-data-forge';
@@ -50,7 +52,11 @@ export const record = <
50
52
  ): Type<RecordTypeFromShape<S>> => {
51
53
  type V = RecordTypeFromShape<S>;
52
54
 
53
- const sourceKeys = new Set(Object.keys(shape));
55
+ // Annotated rather than inferred: the strict standard library types
56
+ // `Object.keys` as the record's own key union, which would make `has` reject
57
+ // the plain `string` keys read back off the value being validated. The
58
+ // membership test is the point here, so the wider element type is correct.
59
+ const sourceKeys: ReadonlySet<string> = new Set(Object.keys(shape));
54
60
 
55
61
  const typeNameFilled: string =
56
62
  options?.typeName ??
@@ -182,24 +188,22 @@ export const record = <
182
188
  // prune keeps only the value paths represented by the shape;
183
189
  // unlike fill, it never fills in missing keys with default values
184
190
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
185
- return Object.fromEntries(
186
- Object.entries(shape).flatMap(([k, v]) => {
187
- // Only optional keys can be absent in the input; required keys are
188
- // statically guaranteed to be present.
189
- if (v.optional === true) {
190
- if (!hasKey(rec, k)) {
191
- return [];
192
- }
191
+ return Obj.filterMap(shape, (v, k) => {
192
+ // Only optional keys can be absent in the input; required keys are
193
+ // statically guaranteed to be present.
194
+ if (v.optional === true) {
195
+ if (!hasKey(rec, k)) {
196
+ return Optional.none;
197
+ }
193
198
 
194
- // For optional fields, if the value is undefined, keep it as undefined
195
- if (rec[k] === undefined) {
196
- return [tp(k, undefined)];
197
- }
199
+ // For optional fields, if the value is undefined, keep it as undefined
200
+ if (rec[k] === undefined) {
201
+ return Optional.some(undefined);
198
202
  }
203
+ }
199
204
 
200
- return [tp(k, v.prune(rec[k]))];
201
- }),
202
- ) as V;
205
+ return Optional.some(v.prune(rec[k]));
206
+ }) as V;
203
207
  };
204
208
 
205
209
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion
@@ -1,4 +1,4 @@
1
- import { expectType } from 'ts-data-forge';
1
+ import { Obj, expectType } from 'ts-data-forge';
2
2
  import {
3
3
  type ArrayElement,
4
4
  type NonEmptyTuple,
@@ -60,10 +60,8 @@ export const required = <
60
60
  options?.keysToBeRequired ?? Object.keys(shape),
61
61
  );
62
62
 
63
- const requiredShape = Object.fromEntries(
64
- Object.entries(shape).map(
65
- ([k, v]) => [k, keysToBeRequired.has(k) ? makeRequired(v) : v] as const,
66
- ),
63
+ const requiredShape = Obj.map(shape, (v, k) =>
64
+ keysToBeRequired.has(k) ? makeRequired(v) : v,
67
65
  ) satisfies UnknownShape;
68
66
 
69
67
  // eslint-disable-next-line total-functions/no-unsafe-type-assertion