effect-app 4.0.0-beta.102 → 4.0.0-beta.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/Operations.d.ts +40 -0
- package/dist/Operations.d.ts.map +1 -1
- package/dist/Schema.d.ts +31 -0
- package/dist/Schema.d.ts.map +1 -1
- package/dist/Schema.js +19 -2
- package/package.json +1 -1
- package/src/Schema.ts +62 -1
- package/test/schema.test.ts +107 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @effect-app/prelude
|
|
2
2
|
|
|
3
|
+
## 4.0.0-beta.104
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- e944bca: Add `generateGuards` and `generateGuardsFor` to `TaggedUnion` / `ExtendTaggedUnion` for property-scoped type guards.
|
|
8
|
+
|
|
9
|
+
- `generateGuards("key")` — generic per-guard, no need to specify the container type
|
|
10
|
+
- `generateGuardsFor<A>()("key")` — curried, fixes `A` for concrete guard signatures
|
|
11
|
+
|
|
12
|
+
Both return `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property.
|
|
13
|
+
|
|
14
|
+
## 4.0.0-beta.103
|
|
15
|
+
|
|
16
|
+
### Minor Changes
|
|
17
|
+
|
|
18
|
+
- 7119320: Add `generateGuards` to `TaggedUnion` / `ExtendTaggedUnion` for generating property-scoped type guards.
|
|
19
|
+
|
|
20
|
+
Usage: `MyUnion.generateGuards<MyType>()("propertyKey")` returns `{ is{Tag}, isAnyOf }` guards that narrow the container type by its tagged union property.
|
|
21
|
+
|
|
3
22
|
## 4.0.0-beta.102
|
|
4
23
|
|
|
5
24
|
## 4.0.0-beta.101
|
package/dist/Operations.d.ts
CHANGED
|
@@ -57,6 +57,26 @@ export declare const OperationResult: S.Union<[typeof OperationSuccess, typeof O
|
|
|
57
57
|
};
|
|
58
58
|
} & {
|
|
59
59
|
readonly tags: import("effect/Schema").Literals<["OperationSuccess", "OperationFailure"]>;
|
|
60
|
+
readonly generateGuards: <K extends string>(property: K) => {
|
|
61
|
+
readonly isOperationSuccess: <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: OperationSuccess; };
|
|
62
|
+
readonly isOperationFailure: <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: OperationFailure; };
|
|
63
|
+
} & {
|
|
64
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: Extract<OperationSuccess, {
|
|
65
|
+
readonly _tag: Tags[number];
|
|
66
|
+
}> | Extract<OperationFailure, {
|
|
67
|
+
readonly _tag: Tags[number];
|
|
68
|
+
}>; };
|
|
69
|
+
};
|
|
70
|
+
readonly generateGuardsFor: <A>() => <K extends { [K_1 in keyof A & string]: A[K_1] extends OperationSuccess | OperationFailure ? K_1 : never; }[keyof A & string]>(property: K) => {
|
|
71
|
+
readonly isOperationSuccess: (target: A) => target is A & { readonly [P in K]: OperationSuccess; };
|
|
72
|
+
readonly isOperationFailure: (target: A) => target is A & { readonly [P in K]: OperationFailure; };
|
|
73
|
+
} & {
|
|
74
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => (target: A) => target is A & { readonly [P in K]: Extract<OperationSuccess, {
|
|
75
|
+
readonly _tag: Tags[number];
|
|
76
|
+
}> | Extract<OperationFailure, {
|
|
77
|
+
readonly _tag: Tags[number];
|
|
78
|
+
}>; };
|
|
79
|
+
};
|
|
60
80
|
};
|
|
61
81
|
export type OperationResult = S.Schema.Type<typeof OperationResult>;
|
|
62
82
|
declare const Operation_base: S.EnhancedClass<Operation, S.Struct<{
|
|
@@ -95,6 +115,26 @@ declare const Operation_base: S.EnhancedClass<Operation, S.Struct<{
|
|
|
95
115
|
};
|
|
96
116
|
} & {
|
|
97
117
|
readonly tags: import("effect/Schema").Literals<["OperationSuccess", "OperationFailure"]>;
|
|
118
|
+
readonly generateGuards: <K extends string>(property: K) => {
|
|
119
|
+
readonly isOperationSuccess: <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: OperationSuccess; };
|
|
120
|
+
readonly isOperationFailure: <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: OperationFailure; };
|
|
121
|
+
} & {
|
|
122
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => <T extends { readonly [P in K]: OperationSuccess | OperationFailure; }>(target: T) => target is T & { readonly [P_1 in K]: Extract<OperationSuccess, {
|
|
123
|
+
readonly _tag: Tags[number];
|
|
124
|
+
}> | Extract<OperationFailure, {
|
|
125
|
+
readonly _tag: Tags[number];
|
|
126
|
+
}>; };
|
|
127
|
+
};
|
|
128
|
+
readonly generateGuardsFor: <A>() => <K extends { [K_1 in keyof A & string]: A[K_1] extends OperationSuccess | OperationFailure ? K_1 : never; }[keyof A & string]>(property: K) => {
|
|
129
|
+
readonly isOperationSuccess: (target: A) => target is A & { readonly [P in K]: OperationSuccess; };
|
|
130
|
+
readonly isOperationFailure: (target: A) => target is A & { readonly [P in K]: OperationFailure; };
|
|
131
|
+
} & {
|
|
132
|
+
readonly isAnyOf: <const Tags extends readonly ("OperationSuccess" | "OperationFailure")[]>(tags: Tags) => (target: A) => target is A & { readonly [P in K]: Extract<OperationSuccess, {
|
|
133
|
+
readonly _tag: Tags[number];
|
|
134
|
+
}> | Extract<OperationFailure, {
|
|
135
|
+
readonly _tag: Tags[number];
|
|
136
|
+
}>; };
|
|
137
|
+
};
|
|
98
138
|
}>;
|
|
99
139
|
createdAt: S.withConstructorDefault<S.DateFromString>;
|
|
100
140
|
updatedAt: S.withConstructorDefault<import("effect/Schema").NullOr<S.DateFromString & {
|
package/dist/Operations.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../src/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAEhC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAA;AACpC,eAAO,MAAM,WAAW;;;;;;CAAa,CAAA;;;;;;;;;AAErC,qBAAa,iBAAkB,SAAQ,sBAMrC;CAAG;;;;;;AAEL,qBAAa,gBACX,SAAQ,qBAEN;CACF;;;;;;AAEF,qBAAa,gBACX,SAAQ,qBAEN;CACF;AAEF,eAAO,MAAM,eAAe
|
|
1
|
+
{"version":3,"file":"Operations.d.ts","sourceRoot":"","sources":["../src/Operations.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,aAAa,CAAA;AAEhC,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,QAAQ,CAAA;AACpC,eAAO,MAAM,WAAW;;;;;;CAAa,CAAA;;;;;;;;;AAErC,qBAAa,iBAAkB,SAAQ,sBAMrC;CAAG;;;;;;AAEL,qBAAa,gBACX,SAAQ,qBAEN;CACF;;;;;;AAEF,qBAAa,gBACX,SAAQ,qBAEN;CACF;AAEF,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAoD,CAAA;AAChF,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,eAAe,CAAC,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEnE,qBAAa,SAAU,SAAQ,cAO7B;CAAG;AAKL,yBAAiB,iBAAiB,CAAC;IACjC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACzF;AACD,yBAAiB,gBAAgB,CAAC;IAChC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACxF;AACD,yBAAiB,gBAAgB,CAAC;IAChC,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KAAG;CACxF;AACD,yBAAiB,SAAS,CAAC;IACzB,UAAiB,OAAQ,SAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,SAAS,CAAC,QAAQ,CAAC,CAAC;KAAG;CACjF"}
|
package/dist/Schema.d.ts
CHANGED
|
@@ -44,8 +44,39 @@ type TaggedUnionMembers = NonEmptyReadonlyArray<S.Top & {
|
|
|
44
44
|
type TaggedUnionTags<Members extends TaggedUnionMembers> = S.Literals<{
|
|
45
45
|
[Index in keyof Members]: Members[Index]["Type"]["_tag"];
|
|
46
46
|
}>;
|
|
47
|
+
type TaggedPropertyKeys<A, Members extends TaggedUnionMembers> = {
|
|
48
|
+
[K in keyof A & string]: A[K] extends Members[number]["Type"] ? K : never;
|
|
49
|
+
}[keyof A & string];
|
|
50
|
+
type PropertyGuardsFor<Members extends TaggedUnionMembers, K extends string, A> = {
|
|
51
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: (target: A) => target is A & {
|
|
52
|
+
readonly [P in K]: M["Type"];
|
|
53
|
+
};
|
|
54
|
+
} & {
|
|
55
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(tags: Tags) => (target: A) => target is A & {
|
|
56
|
+
readonly [P in K]: Extract<Members[number]["Type"], {
|
|
57
|
+
readonly _tag: Tags[number];
|
|
58
|
+
}>;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
type PropertyGuards<Members extends TaggedUnionMembers, K extends string> = {
|
|
62
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: <T extends {
|
|
63
|
+
readonly [P in K]: Members[number]["Type"];
|
|
64
|
+
}>(target: T) => target is T & {
|
|
65
|
+
readonly [P in K]: M["Type"];
|
|
66
|
+
};
|
|
67
|
+
} & {
|
|
68
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(tags: Tags) => <T extends {
|
|
69
|
+
readonly [P in K]: Members[number]["Type"];
|
|
70
|
+
}>(target: T) => target is T & {
|
|
71
|
+
readonly [P in K]: Extract<Members[number]["Type"], {
|
|
72
|
+
readonly _tag: Tags[number];
|
|
73
|
+
}>;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
47
76
|
type TaggedUnionWithTags<Members extends TaggedUnionMembers> = S.toTaggedUnion<"_tag", Members> & {
|
|
48
77
|
readonly tags: TaggedUnionTags<Members>;
|
|
78
|
+
readonly generateGuards: <K extends string>(property: K) => PropertyGuards<Members, K>;
|
|
79
|
+
readonly generateGuardsFor: <A>() => <K extends TaggedPropertyKeys<A, Members>>(property: K) => PropertyGuardsFor<Members, K, A>;
|
|
49
80
|
};
|
|
50
81
|
export declare const ExtendTaggedUnion: <Members extends TaggedUnionMembers>(schema: S.Union<Members>) => TaggedUnionWithTags<Members>;
|
|
51
82
|
export declare const TaggedUnion: <Members extends TaggedUnionMembers>(...a: Members) => TaggedUnionWithTags<Members>;
|
package/dist/Schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"Schema.d.ts","sourceRoot":"","sources":["../src/Schema.ts"],"names":[],"mappings":"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"}
|
package/dist/Schema.js
CHANGED
|
@@ -71,7 +71,24 @@ function collectSentinelsFromAST(ast) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
export const tags = (self) => S.Literals(self.map(getTagFromAST));
|
|
74
|
-
const extendTaggedUnionWithTags = (schema) => extendM(schema.pipe(S.toTaggedUnion("_tag")), () =>
|
|
74
|
+
const extendTaggedUnionWithTags = (schema) => extendM(schema.pipe(S.toTaggedUnion("_tag")), (tagged) => {
|
|
75
|
+
const makeGuards = (property) => {
|
|
76
|
+
const result = {};
|
|
77
|
+
for (const [tag, guard] of Object.entries(tagged.guards)) {
|
|
78
|
+
result[`is${tag}`] = (target) => guard(target[property]);
|
|
79
|
+
}
|
|
80
|
+
result.isAnyOf = (memberTags) => {
|
|
81
|
+
const check = tagged.isAnyOf(memberTags);
|
|
82
|
+
return (target) => check(target[property]);
|
|
83
|
+
};
|
|
84
|
+
return result;
|
|
85
|
+
};
|
|
86
|
+
return {
|
|
87
|
+
tags: tags(schema.members),
|
|
88
|
+
generateGuards: makeGuards,
|
|
89
|
+
generateGuardsFor: () => makeGuards
|
|
90
|
+
};
|
|
91
|
+
});
|
|
75
92
|
export const ExtendTaggedUnion = (schema) => extendTaggedUnionWithTags(schema);
|
|
76
93
|
export const TaggedUnion = (...a) => extendTaggedUnionWithTags(S.Union(a));
|
|
77
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
94
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiU2NoZW1hLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL1NjaGVtYS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFlLE1BQU0sUUFBUSxDQUFBO0FBQy9DLE9BQU8sS0FBSyxDQUFDLE1BQU0sZUFBZSxDQUFBO0FBRWxDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFDckMsT0FBTyxFQUFFLEtBQUssSUFBSSxNQUFNLEVBQTJCLE1BQU0sbUJBQW1CLENBQUE7QUFDNUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGlCQUFpQixDQUFBO0FBQ2pELE9BQU8sRUFBRSxXQUFXLElBQUksWUFBWSxFQUF1QyxNQUFNLHlCQUF5QixDQUFBO0FBQzFHLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxZQUFZLENBQUE7QUFFcEMsY0FBYyxlQUFlLENBQUE7QUFFN0IsY0FBYyxtQkFBbUIsQ0FBQTtBQUNqQyxPQUFPLEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBRXRELE9BQU8sRUFBRSxTQUFTLEVBQUUsT0FBTyxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDdEQsT0FBTyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLGNBQWMsRUFBRSxTQUFTLEVBQUUsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxXQUFXLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM3SSxPQUFPLEVBQUUsR0FBRyxFQUFFLGNBQWMsRUFBRSxNQUFNLHFCQUFxQixDQUFBO0FBRXpELGNBQWMsbUJBQW1CLENBQUE7QUFDakMsY0FBYyxpQkFBaUIsQ0FBQTtBQUMvQixjQUFjLHlCQUF5QixDQUFBO0FBQ3ZDLGNBQWMscUJBQXFCLENBQUE7QUFDbkMsY0FBYyx5QkFBeUIsQ0FBQTtBQUN2QyxjQUFjLG9CQUFvQixDQUFBO0FBQ2xD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
|
package/package.json
CHANGED
package/src/Schema.ts
CHANGED
|
@@ -125,13 +125,74 @@ type TaggedUnionTags<Members extends TaggedUnionMembers> = S.Literals<
|
|
|
125
125
|
}
|
|
126
126
|
>
|
|
127
127
|
|
|
128
|
+
type TaggedPropertyKeys<A, Members extends TaggedUnionMembers> = {
|
|
129
|
+
[K in keyof A & string]: A[K] extends Members[number]["Type"] ? K : never
|
|
130
|
+
}[keyof A & string]
|
|
131
|
+
|
|
132
|
+
type PropertyGuardsFor<
|
|
133
|
+
Members extends TaggedUnionMembers,
|
|
134
|
+
K extends string,
|
|
135
|
+
A
|
|
136
|
+
> =
|
|
137
|
+
& {
|
|
138
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: (
|
|
139
|
+
target: A
|
|
140
|
+
) => target is A & { readonly [P in K]: M["Type"] }
|
|
141
|
+
}
|
|
142
|
+
& {
|
|
143
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(
|
|
144
|
+
tags: Tags
|
|
145
|
+
) => (
|
|
146
|
+
target: A
|
|
147
|
+
) => target is A & { readonly [P in K]: Extract<Members[number]["Type"], { readonly _tag: Tags[number] }> }
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
type PropertyGuards<
|
|
151
|
+
Members extends TaggedUnionMembers,
|
|
152
|
+
K extends string
|
|
153
|
+
> =
|
|
154
|
+
& {
|
|
155
|
+
readonly [M in Members[number] as `is${M["Type"]["_tag"]}`]: <
|
|
156
|
+
T extends { readonly [P in K]: Members[number]["Type"] }
|
|
157
|
+
>(target: T) => target is T & { readonly [P in K]: M["Type"] }
|
|
158
|
+
}
|
|
159
|
+
& {
|
|
160
|
+
readonly isAnyOf: <const Tags extends ReadonlyArray<Members[number]["Type"]["_tag"]>>(
|
|
161
|
+
tags: Tags
|
|
162
|
+
) => <T extends { readonly [P in K]: Members[number]["Type"] }>(
|
|
163
|
+
target: T
|
|
164
|
+
) => target is T & { readonly [P in K]: Extract<Members[number]["Type"], { readonly _tag: Tags[number] }> }
|
|
165
|
+
}
|
|
166
|
+
|
|
128
167
|
type TaggedUnionWithTags<Members extends TaggedUnionMembers> = S.toTaggedUnion<"_tag", Members> & {
|
|
129
168
|
readonly tags: TaggedUnionTags<Members>
|
|
169
|
+
readonly generateGuards: <K extends string>(property: K) => PropertyGuards<Members, K>
|
|
170
|
+
readonly generateGuardsFor: <A>() => <K extends TaggedPropertyKeys<A, Members>>(
|
|
171
|
+
property: K
|
|
172
|
+
) => PropertyGuardsFor<Members, K, A>
|
|
130
173
|
}
|
|
131
174
|
|
|
132
175
|
const extendTaggedUnionWithTags = <Members extends TaggedUnionMembers>(
|
|
133
176
|
schema: S.Union<Members>
|
|
134
|
-
): TaggedUnionWithTags<Members> =>
|
|
177
|
+
): TaggedUnionWithTags<Members> =>
|
|
178
|
+
extendM(schema.pipe(S.toTaggedUnion("_tag")), (tagged) => {
|
|
179
|
+
const makeGuards = (property: string) => {
|
|
180
|
+
const result: any = {}
|
|
181
|
+
for (const [tag, guard] of Object.entries(tagged.guards) as Array<[string, (u: unknown) => boolean]>) {
|
|
182
|
+
result[`is${tag}`] = (target: any) => guard(target[property])
|
|
183
|
+
}
|
|
184
|
+
result.isAnyOf = (memberTags: Array<string>) => {
|
|
185
|
+
const check = tagged.isAnyOf(memberTags)
|
|
186
|
+
return (target: any) => check(target[property])
|
|
187
|
+
}
|
|
188
|
+
return result
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
tags: tags(schema.members),
|
|
192
|
+
generateGuards: makeGuards,
|
|
193
|
+
generateGuardsFor: () => makeGuards
|
|
194
|
+
}
|
|
195
|
+
})
|
|
135
196
|
|
|
136
197
|
export const ExtendTaggedUnion = <Members extends TaggedUnionMembers>(
|
|
137
198
|
schema: S.Union<Members>
|
package/test/schema.test.ts
CHANGED
|
@@ -416,3 +416,110 @@ describe("JSON Schema", () => {
|
|
|
416
416
|
})
|
|
417
417
|
})
|
|
418
418
|
})
|
|
419
|
+
|
|
420
|
+
describe("generateGuards", () => {
|
|
421
|
+
const StateSchema = S.TaggedUnion(
|
|
422
|
+
S.TaggedStruct("Active", { since: S.String }),
|
|
423
|
+
S.TaggedStruct("Inactive", { reason: S.String }),
|
|
424
|
+
S.TaggedStruct("Pending", { eta: S.Finite })
|
|
425
|
+
)
|
|
426
|
+
|
|
427
|
+
type State = S.Schema.Type<typeof StateSchema>
|
|
428
|
+
type Entity = { readonly state: State; readonly name: string }
|
|
429
|
+
|
|
430
|
+
const { isActive, isAnyOf, isInactive, isPending } = StateSchema.generateGuards("state")
|
|
431
|
+
|
|
432
|
+
test("isActive narrows to Active member", () => {
|
|
433
|
+
const entity: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
434
|
+
expect(isActive(entity)).toBe(true)
|
|
435
|
+
if (isActive(entity)) {
|
|
436
|
+
expectTypeOf(entity.state).toEqualTypeOf<{ readonly _tag: "Active"; readonly since: string }>()
|
|
437
|
+
}
|
|
438
|
+
})
|
|
439
|
+
|
|
440
|
+
test("isActive returns false for non-Active", () => {
|
|
441
|
+
const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" }
|
|
442
|
+
expect(isActive(entity)).toBe(false)
|
|
443
|
+
})
|
|
444
|
+
|
|
445
|
+
test("isInactive narrows to Inactive member", () => {
|
|
446
|
+
const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" }
|
|
447
|
+
expect(isInactive(entity)).toBe(true)
|
|
448
|
+
})
|
|
449
|
+
|
|
450
|
+
test("isPending narrows to Pending member", () => {
|
|
451
|
+
const entity: Entity = { state: { _tag: "Pending", eta: 42 }, name: "foo" }
|
|
452
|
+
expect(isPending(entity)).toBe(true)
|
|
453
|
+
})
|
|
454
|
+
|
|
455
|
+
test("isAnyOf narrows to union of specified members", () => {
|
|
456
|
+
const isActiveOrPending = isAnyOf(["Active", "Pending"])
|
|
457
|
+
const active: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
458
|
+
const pending: Entity = { state: { _tag: "Pending", eta: 5 }, name: "bar" }
|
|
459
|
+
const inactive: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "baz" }
|
|
460
|
+
|
|
461
|
+
expect(isActiveOrPending(active)).toBe(true)
|
|
462
|
+
expect(isActiveOrPending(pending)).toBe(true)
|
|
463
|
+
expect(isActiveOrPending(inactive)).toBe(false)
|
|
464
|
+
|
|
465
|
+
if (isActiveOrPending(active)) {
|
|
466
|
+
expectTypeOf(active.state).toEqualTypeOf<
|
|
467
|
+
{ readonly _tag: "Active"; readonly since: string } | { readonly _tag: "Pending"; readonly eta: number }
|
|
468
|
+
>()
|
|
469
|
+
}
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
test("guards use schema-based validation (built-in guards)", () => {
|
|
473
|
+
expect(StateSchema.guards.Active({ _tag: "Active" })).toBe(false)
|
|
474
|
+
expect(StateSchema.guards.Active({ _tag: "Active", since: "2024-01-01" })).toBe(true)
|
|
475
|
+
})
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
describe("generateGuardsFor", () => {
|
|
479
|
+
const StateSchema = S.TaggedUnion(
|
|
480
|
+
S.TaggedStruct("Active", { since: S.String }),
|
|
481
|
+
S.TaggedStruct("Inactive", { reason: S.String }),
|
|
482
|
+
S.TaggedStruct("Pending", { eta: S.Finite })
|
|
483
|
+
)
|
|
484
|
+
|
|
485
|
+
type State = S.Schema.Type<typeof StateSchema>
|
|
486
|
+
type Entity = { readonly state: State; readonly name: string }
|
|
487
|
+
|
|
488
|
+
const { isActive, isAnyOf } = StateSchema.generateGuardsFor<Entity>()("state")
|
|
489
|
+
|
|
490
|
+
test("isActive narrows to Active member", () => {
|
|
491
|
+
const entity: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
492
|
+
expect(isActive(entity)).toBe(true)
|
|
493
|
+
if (isActive(entity)) {
|
|
494
|
+
expectTypeOf(entity.state).toEqualTypeOf<{ readonly _tag: "Active"; readonly since: string }>()
|
|
495
|
+
}
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
test("isActive returns false for non-Active", () => {
|
|
499
|
+
const entity: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "foo" }
|
|
500
|
+
expect(isActive(entity)).toBe(false)
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
test("isAnyOf narrows to union of specified members", () => {
|
|
504
|
+
const isActiveOrPending = isAnyOf(["Active", "Pending"])
|
|
505
|
+
const active: Entity = { state: { _tag: "Active", since: "2024-01-01" }, name: "foo" }
|
|
506
|
+
const inactive: Entity = { state: { _tag: "Inactive", reason: "expired" }, name: "baz" }
|
|
507
|
+
|
|
508
|
+
expect(isActiveOrPending(active)).toBe(true)
|
|
509
|
+
expect(isActiveOrPending(inactive)).toBe(false)
|
|
510
|
+
})
|
|
511
|
+
|
|
512
|
+
test("ExtendTaggedUnion also exposes generateGuardsFor", () => {
|
|
513
|
+
const union = S.Union([
|
|
514
|
+
S.TaggedStruct("X", { x: S.String }),
|
|
515
|
+
S.TaggedStruct("Y", { y: S.Finite })
|
|
516
|
+
])
|
|
517
|
+
const extended = S.ExtendTaggedUnion(union)
|
|
518
|
+
type Obj = { readonly field: S.Schema.Type<typeof extended> }
|
|
519
|
+
const { isX, isY } = extended.generateGuardsFor<Obj>()("field")
|
|
520
|
+
|
|
521
|
+
expect(isX({ field: { _tag: "X", x: "hi" } })).toBe(true)
|
|
522
|
+
expect(isX({ field: { _tag: "Y", y: 1 } })).toBe(false)
|
|
523
|
+
expect(isY({ field: { _tag: "Y", y: 1 } })).toBe(true)
|
|
524
|
+
})
|
|
525
|
+
})
|