Skip to content

Commit

Permalink
Merge pull request #18 from toomuchdesign/feat/object-closeOnResolve
Browse files Browse the repository at this point in the history
feat: add Object closeOnResolve option
  • Loading branch information
ThomasAribart authored May 4, 2024
2 parents 4d1c559 + c9667a2 commit be33507
Show file tree
Hide file tree
Showing 14 changed files with 215 additions and 25 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ In presence of named properties, open meta-objects additional properties are res
- <code>NamedProperties <i>(?{ [key:string]: meta-type } = {})</i></code>
- <code>RequiredPropertiesKeys <i>(?string union = never)</i></code>
- <code>AdditionalProperties <i>(?meta-type = M.Never)</i></code>: The type of additional properties
- <code>CloseOnResolve <i>(?boolean = false)</i></code>: Ignore `AdditionalProperties` at resolution time
- <code>IsSerialized <i>(?boolean = false)</i></code>: See [deserialization](#-deserialization)
- <code>Deserialized <i>(?type = never)</i></code>: See [deserialization](#-deserialization)

Expand All @@ -296,6 +297,22 @@ type Resolved = M.Resolve<
// notRequired?: null,
// [key: string]: unknown
// }

type ClosedOnResolve = M.Resolve<
M.Object<
{
required: M.Primitive<string>;
notRequired: M.Primitive<null>;
},
"required",
M.Primitive<number>,
false
>
>;
// => {
// req: string,
// notRequired?: null,
// }
```

> ☝️ A meta-object is [non-representable](#✨-meta-types) if one of its required properties value is non-representable:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,4 @@
"url": "https://github.com/ThomasAribart/ts-algebra/issues"
},
"homepage": "https://github.com/ThomasAribart/ts-algebra#readme"
}
}
2 changes: 1 addition & 1 deletion src/meta-types/exclusion/const.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ nonExcludingOpenObject;
const serializedObject: A.Equals<
M.Exclude<
M.Const<{ a: "A" }>,
M.Object<{}, never, M.Const<"C">, true, { a: string }>
M.Object<{}, never, M.Const<"C">, false, true, { a: string }>
>,
M.Const<{ a: "A" }>
> = 1;
Expand Down
2 changes: 1 addition & 1 deletion src/meta-types/exclusion/enum.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ nonExcludingOpenObject;
const serializedObject: A.Equals<
M.Exclude<
M.Enum<{ a: "A" } | { a: "B" }>,
M.Object<{}, never, M.Const<"C">, true, { a: "A" }>
M.Object<{}, never, M.Const<"C">, false, true, { a: "A" }>
>,
M.Enum<{ a: "A" } | { a: "B" }>
> = 1;
Expand Down
4 changes: 4 additions & 0 deletions src/meta-types/exclusion/object.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import type { EnumType } from "../enum";
import type { Never, NeverType } from "../never";
import type {
_Object,
IsObjectClosedOnResolve,
IsObjectOpen,
ObjectOpenProps,
ObjectRequiredKeys,
Expand Down Expand Up @@ -268,6 +269,7 @@ type PropagateExclusions<
},
ObjectRequiredKeys<META_OBJECT>,
ObjectOpenProps<META_OBJECT>,
IsObjectClosedOnResolve<META_OBJECT>,
IsSerialized<META_OBJECT>,
Deserialized<META_OBJECT>
>;
Expand Down Expand Up @@ -301,6 +303,7 @@ type OmitOmittableKeys<
},
ObjectRequiredKeys<META_OBJECT>,
ObjectOpenProps<META_OBJECT>,
IsObjectClosedOnResolve<META_OBJECT>,
IsSerialized<META_OBJECT>,
Deserialized<META_OBJECT>
>
Expand Down Expand Up @@ -343,6 +346,7 @@ type ExcludeConstFromObject<
},
Extract<keyof CONST_VALUE, string>,
Never,
IsObjectClosedOnResolve<META_OBJECT>,
IsSerialized<META_CONST>,
Deserialized<META_CONST>
>
Expand Down
56 changes: 50 additions & 6 deletions src/meta-types/exclusion/object.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const bothClosedTooManyOmittableKeys: A.Equals<
> = 1;
bothClosedTooManyOmittableKeys;

// Closed source open excluded
// Source: closed - Excluded: open
const closedSourceOpenExcluded1: A.Equals<
M.Exclude<
M.Object<{ a: M.Enum<"A" | "B">; b: M.Const<"B"> }, "a">,
Expand All @@ -257,7 +257,7 @@ const closedSourceOpenExcluded2: A.Equals<
> = 1;
closedSourceOpenExcluded2;

// Open source closed excluded
// Source: open - Excluded: closed
const openSourceClosedExcluded: A.Equals<
M.Exclude<
M.Object<{ a: M.Const<"A"> }, "a", M.Any>,
Expand Down Expand Up @@ -326,12 +326,48 @@ const bothOpenKeyAdded: A.Equals<
> = 1;
bothOpenKeyAdded;

// close on resolve
const propagatedCloseOnResolve: A.Equals<
M.Exclude<
M.Object<{ a: M.Enum<"A" | "B"> }, "a", M.Never, true>,
M.Object<{ a: M.Const<"B"> }, "a">
>,
M.Object<{ a: M.Enum<"A"> }, "a", M.Never, true>
> = 1;
propagatedCloseOnResolve;

const omittableKeyCloseOnResolve: A.Equals<
M.Exclude<
M.Object<{ a: M.Const<"A">; b: M.Const<"B"> }, "a", M.Never, true>,
M.Object<{ a: M.Const<"A">; b: M.Const<"B"> }, "a" | "b">
>,
M.Object<{ a: M.Const<"A">; b: M.Never }, "a", M.Never, true>
> = 1;
omittableKeyCloseOnResolve;

const excludedCloseOnResolveIsNotUsed: A.Equals<
M.Exclude<
M.Object<{ a: M.Enum<"A" | "B"> }, "a">,
M.Object<{ a: M.Const<"B"> }, "a", M.Never, true>
>,
M.Object<{ a: M.Enum<"A"> }, "a">
> = 1;
excludedCloseOnResolveIsNotUsed;

// Serialization
const propagatedSerialization: A.Equals<
M.Exclude<
M.Object<{ a: M.Enum<"A" | "B"> }, "a", M.Never, true, { a: string }>,
M.Object<
{ a: M.Enum<"A" | "B"> },
"a",
M.Never,
false,
true,
{ a: string }
>,
M.Object<{ a: M.Const<"B"> }, "a">
>,
M.Object<{ a: M.Enum<"A"> }, "a", M.Never, true, { a: string }>
M.Object<{ a: M.Enum<"A"> }, "a", M.Never, false, true, { a: string }>
> = 1;
propagatedSerialization;

Expand All @@ -341,19 +377,27 @@ const omittableKeySerialization: A.Equals<
{ a: M.Const<"A">; b: M.Const<"B"> },
"a",
M.Never,
false,
true,
{ a: string }
>,
M.Object<{ a: M.Const<"A">; b: M.Const<"B"> }, "a" | "b">
>,
M.Object<{ a: M.Const<"A">; b: M.Never }, "a", M.Never, true, { a: string }>
M.Object<
{ a: M.Const<"A">; b: M.Never },
"a",
M.Never,
false,
true,
{ a: string }
>
> = 1;
omittableKeySerialization;

const excludedSerializationIsNotUsed: A.Equals<
M.Exclude<
M.Object<{ a: M.Enum<"A" | "B"> }, "a">,
M.Object<{ a: M.Const<"B"> }, "a", M.Never, true, { a: string }>
M.Object<{ a: M.Const<"B"> }, "a", M.Never, false, true, { a: string }>
>,
M.Object<{ a: M.Enum<"A"> }, "a">
> = 1;
Expand Down
2 changes: 2 additions & 0 deletions src/meta-types/intersection/any.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { ConstType } from "../const";
import type { EnumType, EnumValues } from "../enum";
import type { Never, NeverType } from "../never";
import type {
IsObjectClosedOnResolve,
ObjectOpenProps,
ObjectRequiredKeys,
ObjectType,
Expand Down Expand Up @@ -67,6 +68,7 @@ export type IntersectAny<
ObjectValues<META_TYPE>,
ObjectRequiredKeys<META_TYPE>,
ObjectOpenProps<META_TYPE>,
IsObjectClosedOnResolve<META_TYPE>,
META_TYPE,
META_ANY
>
Expand Down
21 changes: 19 additions & 2 deletions src/meta-types/intersection/any.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,19 @@ const anyToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
>,
M.Object<{ date: M.Primitive<string> }, "date", M.Never, true, { date: Date }>
M.Object<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
> = 1;
anyToSerializedObject;

Expand All @@ -194,7 +202,14 @@ const serializedAnyToObject: A.Equals<
M.Any<true, { date: Date }>,
M.Object<{ date: M.Primitive<string> }, "date">
>,
M.Object<{ date: M.Primitive<string> }, "date", M.Never, true, { date: Date }>
M.Object<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
> = 1;
serializedAnyToObject;

Expand All @@ -205,6 +220,7 @@ const serializedAnyToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
Expand All @@ -213,6 +229,7 @@ const serializedAnyToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date } & { date: Date }
>
Expand Down
2 changes: 2 additions & 0 deletions src/meta-types/intersection/const.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ const constToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
Expand All @@ -304,6 +305,7 @@ const serializedConstToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
Expand Down
2 changes: 2 additions & 0 deletions src/meta-types/intersection/enum.type.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ const enumToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
Expand Down Expand Up @@ -321,6 +322,7 @@ const serializedEnumToSerializedObject: A.Equals<
{ date: M.Primitive<string> },
"date",
M.Never,
false,
true,
{ date: Date }
>
Expand Down
13 changes: 13 additions & 0 deletions src/meta-types/intersection/object.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import type { Or } from "~/utils";

import type { AnyType } from "../any";
import type { ArrayType } from "../array";
import type { ConstType } from "../const";
import type { EnumType } from "../enum";
import type { Never, NeverType } from "../never";
import type {
_$Object,
IsObjectClosedOnResolve,
ObjectOpenProps,
ObjectRequiredKeys,
ObjectType,
Expand Down Expand Up @@ -34,12 +37,14 @@ export type IntersectObjectSerializationParams<
VALUES extends Record<string, Type>,
REQUIRED_KEYS extends string,
OPEN_PROPS extends Type,
CLOSE_ON_RESOLVE extends boolean,
META_OBJECT extends ObjectType,
SERIALIZABLE_META_TYPE extends SerializableType,
> = $MergeObjectPropsToSerializable<
VALUES,
REQUIRED_KEYS,
OPEN_PROPS,
CLOSE_ON_RESOLVE,
META_OBJECT,
SERIALIZABLE_META_TYPE
>;
Expand All @@ -57,12 +62,14 @@ type $MergeObjectPropsToSerializable<
VALUES,
REQUIRED_KEYS,
OPEN_PROPS,
CLOSE_ON_RESOLVE,
META_OBJECT extends ObjectType,
SERIALIZABLE_META_TYPE extends SerializableType,
> = _$Object<
VALUES,
REQUIRED_KEYS,
OPEN_PROPS,
CLOSE_ON_RESOLVE,
IntersectIsSerialized<META_OBJECT, SERIALIZABLE_META_TYPE>,
IntersectDeserialized<META_OBJECT, SERIALIZABLE_META_TYPE>
>;
Expand All @@ -84,6 +91,7 @@ export type IntersectObject<
ObjectValues<META_OBJECT>,
ObjectRequiredKeys<META_OBJECT>,
ObjectOpenProps<META_OBJECT>,
IsObjectClosedOnResolve<META_OBJECT>,
META_OBJECT,
META_TYPE
>
Expand Down Expand Up @@ -121,12 +129,17 @@ type IntersectObjects<
ObjectOpenProps<META_OBJECT_A>,
ObjectOpenProps<META_OBJECT_B>
>,
INTERSECTED_CLOSE_ON_RESOLVE = Or<
IsObjectClosedOnResolve<META_OBJECT_A>,
IsObjectClosedOnResolve<META_OBJECT_B>
>,
> = $MergeObjectPropsToSerializable<
{
[KEY in keyof INTERSECTED_VALUES]: INTERSECTED_VALUES[KEY];
},
ObjectRequiredKeys<META_OBJECT_A> | ObjectRequiredKeys<META_OBJECT_B>,
INTERSECTED_OPEN_PROPS,
INTERSECTED_CLOSE_ON_RESOLVE,
META_OBJECT_A,
META_OBJECT_B
>;
Expand Down
Loading

0 comments on commit be33507

Please sign in to comment.