Skip to content

Commit f38987f

Browse files
authored
Merge pull request #55 from lambdalisue/set-map
Add `isSet`, `isSetOf`, `isMap`, and `isMapOf`
2 parents 5b37cf4 + 99ced12 commit f38987f

File tree

4 files changed

+383
-66
lines changed

4 files changed

+383
-66
lines changed

__snapshots__/is_test.ts.snap

Lines changed: 77 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,32 @@
11
export const snapshot = {};
22

3-
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
4-
5-
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
6-
7-
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
8-
9-
snapshot[`isLiteralOf<T> > returns properly named function 1`] = `'isLiteralOf("hello")'`;
10-
11-
snapshot[`isLiteralOf<T> > returns properly named function 2`] = `"isLiteralOf(100)"`;
12-
13-
snapshot[`isLiteralOf<T> > returns properly named function 3`] = `"isLiteralOf(100n)"`;
14-
15-
snapshot[`isLiteralOf<T> > returns properly named function 4`] = `"isLiteralOf(true)"`;
16-
17-
snapshot[`isLiteralOf<T> > returns properly named function 5`] = `"isLiteralOf(null)"`;
18-
19-
snapshot[`isLiteralOf<T> > returns properly named function 6`] = `"isLiteralOf(undefined)"`;
20-
21-
snapshot[`isLiteralOf<T> > returns properly named function 7`] = `"isLiteralOf(Symbol(asdf))"`;
22-
23-
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber)"`;
3+
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
244
25-
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous))"`;
5+
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
266
27-
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
7+
snapshot[`isMapOf<T> > returns properly named function 1`] = `"isMapOf(isNumber)"`;
288
29-
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
9+
snapshot[`isMapOf<T> > returns properly named function 2`] = `"isMapOf((anonymous))"`;
3010
31-
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
11+
snapshot[`isTupleOf<T> > returns properly named function 1`] = `
3212
"isTupleOf([
3313
isNumber,
3414
isString,
3515
isBoolean
36-
], isArray)"
16+
])"
3717
`;
3818
39-
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
19+
snapshot[`isTupleOf<T> > returns properly named function 2`] = `"isTupleOf([(anonymous)])"`;
4020
41-
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
21+
snapshot[`isTupleOf<T> > returns properly named function 3`] = `
4222
"isTupleOf([
4323
isTupleOf([
4424
isTupleOf([
4525
isNumber,
4626
isString,
4727
isBoolean
48-
], isArray)
49-
], isArray)
50-
])"
51-
`;
52-
53-
snapshot[`isAllOf<T> > returns properly named function 1`] = `
54-
"isAllOf([
55-
isObjectOf({a: isNumber}),
56-
isObjectOf({b: isString})
28+
])
29+
])
5730
])"
5831
`;
5932
@@ -65,8 +38,6 @@ snapshot[`isOneOf<T> > returns properly named function 1`] = `
6538
])"
6639
`;
6740
68-
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
69-
7041
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 1`] = `
7142
"isReadonlyTupleOf([
7243
isNumber,
@@ -89,32 +60,26 @@ snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 3`] = `
8960
], isArray)"
9061
`;
9162
92-
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
93-
94-
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
95-
96-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyUniformTupleOf(3, isAny)"`;
63+
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
9764
98-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyUniformTupleOf(3, isNumber)"`;
65+
snapshot[`isSetOf<T> > returns properly named function 1`] = `"isSetOf(isNumber)"`;
9966
100-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyUniformTupleOf(3, (anonymous))"`;
67+
snapshot[`isSetOf<T> > returns properly named function 2`] = `"isSetOf((anonymous))"`;
10168
102-
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
103-
104-
snapshot[`isTupleOf<T> > returns properly named function 1`] = `
105-
"isTupleOf([
69+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
70+
"isReadonlyTupleOf([
10671
isNumber,
10772
isString,
10873
isBoolean
10974
])"
11075
`;
11176
112-
snapshot[`isTupleOf<T> > returns properly named function 2`] = `"isTupleOf([(anonymous)])"`;
77+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyTupleOf([(anonymous)])"`;
11378
114-
snapshot[`isTupleOf<T> > returns properly named function 3`] = `
115-
"isTupleOf([
116-
isTupleOf([
117-
isTupleOf([
79+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
80+
"isReadonlyTupleOf([
81+
isReadonlyTupleOf([
82+
isReadonlyTupleOf([
11883
isNumber,
11984
isString,
12085
isBoolean
@@ -123,29 +88,49 @@ snapshot[`isTupleOf<T> > returns properly named function 3`] = `
12388
])"
12489
`;
12590
91+
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
92+
93+
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
94+
95+
snapshot[`isMapOf<T, K> > returns properly named function 1`] = `"isMapOf(isNumber, isString)"`;
96+
97+
snapshot[`isMapOf<T, K> > returns properly named function 2`] = `"isMapOf((anonymous), isString)"`;
98+
99+
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber)"`;
100+
101+
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous))"`;
102+
126103
snapshot[`isArrayOf<T> > returns properly named function 1`] = `"isArrayOf(isNumber)"`;
127104
128105
snapshot[`isArrayOf<T> > returns properly named function 2`] = `"isArrayOf((anonymous))"`;
129106
130-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
131-
"isReadonlyTupleOf([
107+
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
108+
109+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyUniformTupleOf(3, isAny)"`;
110+
111+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyUniformTupleOf(3, isNumber)"`;
112+
113+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyUniformTupleOf(3, (anonymous))"`;
114+
115+
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
116+
"isTupleOf([
132117
isNumber,
133118
isString,
134119
isBoolean
135-
])"
120+
], isArray)"
136121
`;
137122
138-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyTupleOf([(anonymous)])"`;
123+
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
139124
140-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
141-
"isReadonlyTupleOf([
142-
isReadonlyTupleOf([
143-
isReadonlyTupleOf([
125+
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
126+
"isTupleOf([
127+
isTupleOf([
128+
isTupleOf([
144129
isNumber,
145130
isString,
146131
isBoolean
147-
])
148-
])
132+
], isArray)
133+
], isArray)
149134
])"
150135
`;
151136
@@ -166,3 +151,30 @@ snapshot[`isObjectOf<T> > returns properly named function 3`] = `
166151
})
167152
})"
168153
`;
154+
155+
snapshot[`isLiteralOf<T> > returns properly named function 1`] = `'isLiteralOf("hello")'`;
156+
157+
snapshot[`isLiteralOf<T> > returns properly named function 2`] = `"isLiteralOf(100)"`;
158+
159+
snapshot[`isLiteralOf<T> > returns properly named function 3`] = `"isLiteralOf(100n)"`;
160+
161+
snapshot[`isLiteralOf<T> > returns properly named function 4`] = `"isLiteralOf(true)"`;
162+
163+
snapshot[`isLiteralOf<T> > returns properly named function 5`] = `"isLiteralOf(null)"`;
164+
165+
snapshot[`isLiteralOf<T> > returns properly named function 6`] = `"isLiteralOf(undefined)"`;
166+
167+
snapshot[`isLiteralOf<T> > returns properly named function 7`] = `"isLiteralOf(Symbol(asdf))"`;
168+
169+
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
170+
171+
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
172+
173+
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
174+
175+
snapshot[`isAllOf<T> > returns properly named function 1`] = `
176+
"isAllOf([
177+
isObjectOf({a: isNumber}),
178+
isObjectOf({b: isString})
179+
])"
180+
`;

is.ts

Lines changed: 131 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,60 @@ export function isArrayOf<T>(
178178
);
179179
}
180180

181+
/**
182+
* Return `true` if the type of `x` is `Set<unknown>`.
183+
*
184+
* ```ts
185+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
186+
*
187+
* const a: unknown = new Set([0, 1, 2]);
188+
* if (is.Set(a)) {
189+
* // a is narrowed to Set<unknown>
190+
* const _: Set<unknown> = a;
191+
* }
192+
* ```
193+
*/
194+
export const isSet = Object.defineProperties(isInstanceOf(Set), {
195+
name: {
196+
value: "isSet",
197+
},
198+
});
199+
200+
/**
201+
* Return a type predicate function that returns `true` if the type of `x` is `Set<T>`.
202+
*
203+
* To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
204+
*
205+
* ```ts
206+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
207+
*
208+
* const isMyType = is.SetOf(is.String);
209+
* const a: unknown = new Set(["a", "b", "c"]);
210+
* if (isMyType(a)) {
211+
* // a is narrowed to Set<string>
212+
* const _: Set<string> = a;
213+
* }
214+
* ```
215+
*/
216+
export function isSetOf<T>(
217+
pred: Predicate<T>,
218+
): Predicate<Set<T>> {
219+
return Object.defineProperties(
220+
(x: unknown): x is Set<T> => {
221+
if (!isSet(x)) return false;
222+
for (const v of x.values()) {
223+
if (!pred(v)) return false;
224+
}
225+
return true;
226+
},
227+
{
228+
name: {
229+
get: () => `isSetOf(${inspect(pred)})`,
230+
},
231+
},
232+
);
233+
}
234+
181235
/**
182236
* Tuple type of types that are predicated by an array of predicate functions.
183237
*
@@ -547,7 +601,7 @@ export type RecordOf<T, K extends PropertyKey = PropertyKey> = Record<K, T>;
547601
export function isRecord(
548602
x: unknown,
549603
): x is Record<PropertyKey, unknown> {
550-
if (isNullish(x) || isArray(x)) {
604+
if (isNullish(x) || isArray(x) || isSet(x) || isMap(x)) {
551605
return false;
552606
}
553607
return typeof x === "object";
@@ -605,6 +659,78 @@ export function isRecordOf<T, K extends PropertyKey = PropertyKey>(
605659
);
606660
}
607661

662+
/**
663+
* Return `true` if the type of `x` is `Map<unknown, unknown>`.
664+
*
665+
* ```ts
666+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
667+
*
668+
* const a: unknown = new Map([["a", 0], ["b", 1]]);
669+
* if (is.Map(a)) {
670+
* // a is narrowed to Map<unknown, unknown>
671+
* const _: Map<unknown, unknown> = a;
672+
* }
673+
* ```
674+
*/
675+
export const isMap = Object.defineProperties(isInstanceOf(Map), {
676+
name: {
677+
value: "isMap",
678+
},
679+
});
680+
681+
/**
682+
* Return a type predicate function that returns `true` if the type of `x` is `Map<K, T>`.
683+
*
684+
* To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
685+
*
686+
* ```ts
687+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
688+
*
689+
* const isMyType = is.MapOf(is.Number);
690+
* const a: unknown = new Map([["a", 0], ["b", 1]]);
691+
* if (isMyType(a)) {
692+
* // a is narrowed to Map<unknown, number>
693+
* const _: Map<unknown, number> = a;
694+
* }
695+
* ```
696+
*
697+
* With predicate function for keys:
698+
*
699+
* ```ts
700+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
701+
*
702+
* const isMyType = is.MapOf(is.Number, is.String);
703+
* const a: unknown = new Map([["a", 0], ["b", 1]]);
704+
* if (isMyType(a)) {
705+
* // a is narrowed to Map<string, number>
706+
* const _: Map<string, number> = a;
707+
* }
708+
* ```
709+
*/
710+
export function isMapOf<T, K>(
711+
pred: Predicate<T>,
712+
predKey?: Predicate<K>,
713+
): Predicate<Map<K, T>> {
714+
return Object.defineProperties(
715+
(x: unknown): x is Map<K, T> => {
716+
if (!isMap(x)) return false;
717+
for (const entry of x.entries()) {
718+
const [k, v] = entry;
719+
if (!pred(v)) return false;
720+
if (predKey && !predKey(k)) return false;
721+
}
722+
return true;
723+
},
724+
{
725+
name: {
726+
get: predKey
727+
? () => `isMapOf(${inspect(pred)}, ${inspect(predKey)})`
728+
: () => `isMapOf(${inspect(pred)})`,
729+
},
730+
},
731+
);
732+
}
733+
608734
type FlatType<T> = T extends RecordOf<unknown>
609735
? { [K in keyof T]: FlatType<T[K]> }
610736
: T;
@@ -1111,12 +1237,16 @@ export default {
11111237
Boolean: isBoolean,
11121238
Array: isArray,
11131239
ArrayOf: isArrayOf,
1240+
Set: isSet,
1241+
SetOf: isSetOf,
11141242
TupleOf: isTupleOf,
11151243
ReadonlyTupleOf: isReadonlyTupleOf,
11161244
UniformTupleOf: isUniformTupleOf,
11171245
ReadonlyUniformTupleOf: isReadonlyUniformTupleOf,
11181246
Record: isRecord,
11191247
RecordOf: isRecordOf,
1248+
Map: isMap,
1249+
MapOf: isMapOf,
11201250
ObjectOf: isObjectOf,
11211251
Function: isFunction,
11221252
SyncFunction: isSyncFunction,

0 commit comments

Comments
 (0)