Skip to content

Commit 94aa3f8

Browse files
authored
Add AndAll type (#1383)
1 parent 4c42d89 commit 94aa3f8

File tree

6 files changed

+145
-2
lines changed

6 files changed

+145
-2
lines changed

index.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ export type {IsNull} from './source/is-null.d.ts';
155155
export type {IfNull} from './source/if-null.d.ts';
156156
export type {IsUndefined} from './source/is-undefined.d.ts';
157157
export type {And} from './source/and.d.ts';
158+
export type {AndAll} from './source/and-all.d.ts';
158159
export type {Or} from './source/or.d.ts';
159160
export type {OrAll} from './source/or-all.d.ts';
160161
export type {Xor} from './source/xor.d.ts';

readme.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ Click the type names for complete docs.
183183
- [`And`](source/and.d.ts) - Returns a boolean for whether two given types are both `true`.
184184
- [`Or`](source/or.d.ts) - Returns a boolean for whether either of two given types is `true`.
185185
- [`Xor`](source/xor.d.ts) - Returns a boolean for whether only one of two given types is `true`.
186+
- [`AndAll`](source/and-all.d.ts) - Returns a boolean for whether all of the given elements are `true`.
186187
- [`OrAll`](source/or-all.d.ts) - Returns a boolean for whether any of the given elements is `true`.
187188
- [`AllExtend`](source/all-extend.d.ts) - Returns a boolean for whether every element in an array type extends another type.
188189
- [`SomeExtend`](source/some-extend.d.ts) - Returns a boolean for whether some element in an array type extends another type.

source/and-all.d.ts

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import type {AllExtend} from './all-extend.d.ts';
2+
3+
/**
4+
Returns a boolean for whether all of the given elements are `true`.
5+
6+
Use-cases:
7+
- Check if all conditions in a list of booleans are met.
8+
9+
@example
10+
```
11+
import type {AndAll} from 'type-fest';
12+
13+
type TTT = AndAll<[true, true, true]>;
14+
//=> true
15+
16+
type TTF = AndAll<[true, true, false]>;
17+
//=> false
18+
19+
type TFT = AndAll<[true, false, true]>;
20+
//=> false
21+
```
22+
23+
Note: When `boolean` is passed as an element, it is distributed into separate cases, and the final result is a union of those cases.
24+
For example, `AndAll<[true, boolean]>` expands to `AndAll<[true, true]> | AndAll<[true, false]>`, which simplifies to `true | false` (i.e., `boolean`).
25+
26+
@example
27+
```
28+
import type {AndAll} from 'type-fest';
29+
30+
type A = AndAll<[true, boolean]>;
31+
//=> boolean
32+
33+
type B = AndAll<[false, boolean]>;
34+
//=> false
35+
```
36+
37+
Note: If any of the elements is `never`, the result becomes `false`.
38+
39+
@example
40+
```
41+
import type {AndAll} from 'type-fest';
42+
43+
type A = AndAll<[true, true, never]>;
44+
//=> false
45+
46+
type B = AndAll<[false, never, never]>;
47+
//=> false
48+
49+
type C = AndAll<[never, never, never]>;
50+
//=> false
51+
52+
type D = AndAll<[boolean, true, never]>;
53+
//=> false
54+
```
55+
56+
Note: If `any` is passed as an element, it is treated as `boolean` and the result is computed accordingly.
57+
58+
@example
59+
```
60+
import type {AndAll} from 'type-fest';
61+
62+
type A = AndAll<[false, any]>;
63+
//=> false
64+
65+
type B = AndAll<[true, any]>;
66+
//=> boolean
67+
```
68+
69+
Note: `AndAll<[]>` evaluates to `true` due to the concept of [vacuous truth](https://en.wikipedia.org/wiki/Logical_conjunction#:~:text=In%20keeping%20with%20the%20concept%20of%20vacuous%20truth%2C%20when%20conjunction%20is%20defined%20as%20an%20operator%20or%20function%20of%20arbitrary%20arity%2C%20the%20empty%20conjunction%20(AND%2Ding%20over%20an%20empty%20set%20of%20operands)%20is%20often%20defined%20as%20having%20the%20result%20true.), i.e., there are no `false` elements in an empty tuple.
70+
71+
@see {@link And}
72+
@see {@link OrAll}
73+
*/
74+
export type AndAll<T extends readonly boolean[]> = AllExtend<T, true>;
75+
76+
export {};

source/and.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {AllExtend} from './all-extend.d.ts';
1+
import type {AndAll} from './and-all.d.ts';
22

33
/**
44
Returns a boolean for whether two given types are both true.
@@ -73,9 +73,10 @@ type G = And<never, never>;
7373
//=> false
7474
```
7575
76+
@see {@link AndAll}
7677
@see {@link Or}
7778
@see {@link Xor}
7879
*/
79-
export type And<A extends boolean, B extends boolean> = AllExtend<[A, B], true>;
80+
export type And<A extends boolean, B extends boolean> = AndAll<[A, B]>;
8081

8182
export {};

source/or-all.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ type B = OrAll<[true, any]>;
6666
Note: `OrAll<[]>` evaluates to `false` because there are no `true` elements in an empty tuple. See [Wikipedia: Clause (logic) > Empty clauses](https://en.wikipedia.org/wiki/Clause_(logic)#Empty_clauses:~:text=The%20truth%20evaluation%20of%20an%20empty%20disjunctive%20clause%20is%20always%20false.).
6767
6868
@see {@link Or}
69+
@see {@link AndAll}
6970
*/
7071
export type OrAll<T extends readonly boolean[]> = SomeExtend<T, true>;
7172

test-d/and-all.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {expectType} from 'tsd';
2+
import type {AndAll} from '../source/and-all.d.ts';
3+
4+
declare const boolean: boolean;
5+
6+
// Basic boolean combinations
7+
expectType<AndAll<[true, true]>>(true);
8+
expectType<AndAll<[true, false]>>(false);
9+
expectType<AndAll<[false, true]>>(false);
10+
expectType<AndAll<[false, false]>>(false);
11+
12+
// Multiple elements in a tuple
13+
expectType<AndAll<[true, true, true, true]>>(true);
14+
expectType<AndAll<[true, true, true, false]>>(false);
15+
expectType<AndAll<[true, true, false, true]>>(false);
16+
17+
// `boolean` element
18+
expectType<AndAll<[true, true, boolean]>>(boolean);
19+
expectType<AndAll<[true, boolean, false]>>(false);
20+
expectType<AndAll<[boolean, boolean, boolean]>>(boolean);
21+
22+
// Unions
23+
expectType<AndAll<[true, true, true] | [true, true, false]>>(boolean); // `true` | `false`
24+
expectType<AndAll<[true, true] | [true]>>(true); // `true` | `true`
25+
expectType<AndAll<[false] | [true, false, true]>>(false); // `false` | `false`
26+
expectType<AndAll<[true, true] | [true, boolean]>>(boolean); // `true` | `boolean`
27+
expectType<AndAll<[false, true] | [true, true, boolean]>>(boolean); // `false` | `boolean`
28+
expectType<AndAll<[boolean, true, true] | [boolean]>>(boolean); // `boolean` | `boolean`
29+
30+
// Tuples with rest element
31+
expectType<AndAll<[true, ...Array<true>]>>(true);
32+
expectType<AndAll<[...Array<true>, false]>>(false);
33+
expectType<AndAll<[true, ...Array<true>, boolean]>>(boolean);
34+
35+
// Non-tuple arrays
36+
expectType<AndAll<Array<true>>>(true);
37+
expectType<AndAll<Array<false>>>(false);
38+
expectType<AndAll<boolean[]>>(boolean);
39+
40+
// Readonly arrays
41+
expectType<AndAll<readonly [true, true, true]>>(true);
42+
expectType<AndAll<readonly [true, true, false]>>(false);
43+
expectType<AndAll<readonly [true, true, boolean]>>(boolean);
44+
expectType<AndAll<ReadonlyArray<true>>>(true);
45+
expectType<AndAll<ReadonlyArray<false>>>(false);
46+
expectType<AndAll<readonly boolean[]>>(boolean);
47+
48+
// Boundary cases
49+
expectType<AndAll<[]>>(true);
50+
51+
expectType<AndAll<[any, any, false]>>(false);
52+
expectType<AndAll<[any, any, true]>>(boolean);
53+
expectType<AndAll<[any, any, any]>>(boolean);
54+
55+
expectType<AndAll<[false, never, never]>>(false);
56+
expectType<AndAll<[true, true, never]>>(false);
57+
expectType<AndAll<[never, never, never]>>(false);
58+
59+
// Errors with non-boolean or optional elements
60+
// @ts-expect-error
61+
type Error1 = AndAll<[1, 0]>;
62+
// @ts-expect-error
63+
type Error2 = AndAll<[true, false?]>;

0 commit comments

Comments
 (0)