-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.ts
40 lines (36 loc) · 1.02 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import Guard, { GuardedType } from "../../Guard";
import TValidate from "../TValidate";
/**
* Validates if criterias of two (or more) types are all met.
*
* `guard.name: "<typeA.name> & <typeB.name>"`
*
* @returns
* A `Guard` that is similar in concept as the `&` operator in TypeScript.
* Accepts a value when it was accepted by all `guardA` and `guardB`, and others.
*
*/
export default function TAnd<A, B, T extends Array<Guard<unknown>>>(
guardA: Guard<A>,
guardB: Guard<B>,
...others: T
): Guard<A & B & UnionToIntersection<GuardedType<ArrayType<T>>>> {
const guards = [guardA, guardB, ...others];
return TValidate(
`(${guards.map(({ name }) => name).join(" & ")})`,
(value) => {
for (const guard of guards) {
if (!guard.isValid(value)) return false;
}
return true;
}
);
}
type ArrayType<C extends Array<unknown>> = C extends Array<infer T>
? T
: unknown;
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never;