Skip to content

Commit 172e23a

Browse files
committed
👍 Add isRecordLike and isRecordLikeOf functions
1 parent ee90c24 commit 172e23a

File tree

7 files changed

+286
-115
lines changed

7 files changed

+286
-115
lines changed
Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,19 @@
11
export const snapshot = {};
22

3-
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
4-
5-
snapshot[`isOptionalOf<T> > returns properly named function 2`] = `"isOptionalOf(isNumber)"`;
6-
73
snapshot[`isUnwrapOptionalOf<T> > returns properly named function 1`] = `"isNumber"`;
84
95
snapshot[`isUnwrapOptionalOf<T> > returns properly named function 2`] = `"isNumber"`;
106
117
snapshot[`isUnwrapOptionalOf<T> > returns properly named function 3`] = `"isNumber"`;
128
9+
snapshot[`isReadonlyOf<T> > returns properly named function 1`] = `"isReadonlyOf(isNumber)"`;
10+
11+
snapshot[`isReadonlyOf<T> > returns properly named function 2`] = `"isReadonlyOf(isReadonlyOf(isNumber))"`;
12+
1313
snapshot[`isUnwrapReadonlyOf<T> > returns properly named function 1`] = `"isNumber"`;
1414
1515
snapshot[`isUnwrapReadonlyOf<T> > returns properly named function 2`] = `"isReadonlyOf(isNumber)"`;
1616
17-
snapshot[`isReadonlyOf<T> > returns properly named function 1`] = `"isReadonlyOf(isNumber)"`;
17+
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
1818
19-
snapshot[`isReadonlyOf<T> > returns properly named function 2`] = `"isReadonlyOf(isReadonlyOf(isNumber))"`;
19+
snapshot[`isOptionalOf<T> > returns properly named function 2`] = `"isOptionalOf(isNumber)"`;
Lines changed: 89 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,8 @@
11
export const snapshot = {};
22

3-
snapshot[`isObjectOf<T> > returns properly named function 1`] = `
4-
"isObjectOf({
5-
a: isNumber,
6-
b: isString,
7-
c: isBoolean
8-
})"
9-
`;
10-
11-
snapshot[`isObjectOf<T> > returns properly named function 2`] = `"isObjectOf({a: a})"`;
12-
13-
snapshot[`isObjectOf<T> > returns properly named function 3`] = `
14-
"isObjectOf({
15-
a: isObjectOf({
16-
b: isObjectOf({c: isBoolean})
17-
})
18-
})"
19-
`;
20-
21-
snapshot[`isArrayOf<T> > returns properly named function 1`] = `"isArrayOf(isNumber)"`;
22-
23-
snapshot[`isArrayOf<T> > returns properly named function 2`] = `"isArrayOf((anonymous))"`;
24-
25-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
26-
"isReadonlyOf(isTupleOf([
27-
isNumber,
28-
isString,
29-
isBoolean
30-
]))"
31-
`;
32-
33-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isTupleOf([(anonymous)]))"`;
34-
35-
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
36-
"isReadonlyOf(isTupleOf([
37-
isReadonlyOf(isTupleOf([
38-
isReadonlyOf(isTupleOf([
39-
isNumber,
40-
isString,
41-
isBoolean
42-
]))
43-
]))
44-
]))"
45-
`;
46-
47-
snapshot[`isSetOf<T> > returns properly named function 1`] = `"isSetOf(isNumber)"`;
3+
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
484
49-
snapshot[`isSetOf<T> > returns properly named function 2`] = `"isSetOf((anonymous))"`;
5+
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
506
517
snapshot[`isTupleOf<T> > returns properly named function 1`] = `
528
"isTupleOf([
@@ -70,9 +26,17 @@ snapshot[`isTupleOf<T> > returns properly named function 3`] = `
7026
])"
7127
`;
7228
73-
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber, undefined)"`;
29+
snapshot[`isRecordLikeOf<T> > returns properly named function 1`] = `"isRecordLikeOf(isNumber, undefined)"`;
7430
75-
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous), undefined)"`;
31+
snapshot[`isRecordLikeOf<T> > returns properly named function 2`] = `"isRecordLikeOf((anonymous), undefined)"`;
32+
33+
snapshot[`isRecordLikeOf<T, K> > returns properly named function 1`] = `"isRecordLikeOf(isNumber, isString)"`;
34+
35+
snapshot[`isRecordLikeOf<T, K> > returns properly named function 2`] = `"isRecordLikeOf((anonymous), isString)"`;
36+
37+
snapshot[`isMapOf<T, K> > returns properly named function 1`] = `"isMapOf(isNumber, isString)"`;
38+
39+
snapshot[`isMapOf<T, K> > returns properly named function 2`] = `"isMapOf((anonymous), isString)"`;
7640
7741
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 1`] = `
7842
"isReadonlyOf(isTupleOf([
@@ -96,37 +60,31 @@ snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 3`] = `
9660
], isArray))"
9761
`;
9862
99-
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
100-
"isTupleOf([
101-
isNumber,
102-
isString,
103-
isBoolean
104-
], isArray)"
105-
`;
63+
snapshot[`isMapOf<T> > returns properly named function 1`] = `"isMapOf(isNumber, undefined)"`;
10664
107-
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
65+
snapshot[`isMapOf<T> > returns properly named function 2`] = `"isMapOf((anonymous), undefined)"`;
10866
109-
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
110-
"isTupleOf([
111-
isTupleOf([
112-
isTupleOf([
113-
isNumber,
114-
isString,
115-
isBoolean
116-
], isArray)
117-
], isArray)
118-
])"
67+
snapshot[`isObjectOf<T> > returns properly named function 1`] = `
68+
"isObjectOf({
69+
a: isNumber,
70+
b: isString,
71+
c: isBoolean
72+
})"
11973
`;
12074
121-
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
122-
123-
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
75+
snapshot[`isObjectOf<T> > returns properly named function 2`] = `"isObjectOf({a: a})"`;
12476
125-
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
77+
snapshot[`isObjectOf<T> > returns properly named function 3`] = `
78+
"isObjectOf({
79+
a: isObjectOf({
80+
b: isObjectOf({c: isBoolean})
81+
})
82+
})"
83+
`;
12684
127-
snapshot[`isMapOf<T> > returns properly named function 1`] = `"isMapOf(isNumber, undefined)"`;
85+
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber, undefined)"`;
12886
129-
snapshot[`isMapOf<T> > returns properly named function 2`] = `"isMapOf((anonymous), undefined)"`;
87+
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous), undefined)"`;
13088
13189
snapshot[`isStrictOf<T> > returns properly named function 1`] = `
13290
"isStrictOf(isObjectOf({
@@ -146,10 +104,6 @@ snapshot[`isStrictOf<T> > returns properly named function 3`] = `
146104
}))"
147105
`;
148106
149-
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
150-
151-
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
152-
153107
snapshot[`isLiteralOf<T> > returns properly named function 1`] = `'isLiteralOf("hello")'`;
154108
155109
snapshot[`isLiteralOf<T> > returns properly named function 2`] = `"isLiteralOf(100)"`;
@@ -164,18 +118,72 @@ snapshot[`isLiteralOf<T> > returns properly named function 6`] = `"isLiteralOf(u
164118
165119
snapshot[`isLiteralOf<T> > returns properly named function 7`] = `"isLiteralOf(Symbol(asdf))"`;
166120
167-
snapshot[`isMapOf<T, K> > returns properly named function 1`] = `"isMapOf(isNumber, isString)"`;
121+
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
168122
169-
snapshot[`isMapOf<T, K> > returns properly named function 2`] = `"isMapOf((anonymous), isString)"`;
123+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
124+
"isReadonlyOf(isTupleOf([
125+
isNumber,
126+
isString,
127+
isBoolean
128+
]))"
129+
`;
130+
131+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isTupleOf([(anonymous)]))"`;
132+
133+
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
134+
"isReadonlyOf(isTupleOf([
135+
isReadonlyOf(isTupleOf([
136+
isReadonlyOf(isTupleOf([
137+
isNumber,
138+
isString,
139+
isBoolean
140+
]))
141+
]))
142+
]))"
143+
`;
144+
145+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyOf(isUniformTupleOf(3, isAny))"`;
146+
147+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isUniformTupleOf(3, isNumber))"`;
148+
149+
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyOf(isUniformTupleOf(3, (anonymous)))"`;
170150
171151
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
172152
173153
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
174154
175155
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
176156
177-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyOf(isUniformTupleOf(3, isAny))"`;
157+
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
178158
179-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isUniformTupleOf(3, isNumber))"`;
159+
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
180160
181-
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyOf(isUniformTupleOf(3, (anonymous)))"`;
161+
snapshot[`isArrayOf<T> > returns properly named function 1`] = `"isArrayOf(isNumber)"`;
162+
163+
snapshot[`isArrayOf<T> > returns properly named function 2`] = `"isArrayOf((anonymous))"`;
164+
165+
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
166+
"isTupleOf([
167+
isNumber,
168+
isString,
169+
isBoolean
170+
], isArray)"
171+
`;
172+
173+
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
174+
175+
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
176+
"isTupleOf([
177+
isTupleOf([
178+
isTupleOf([
179+
isNumber,
180+
isString,
181+
isBoolean
182+
], isArray)
183+
], isArray)
184+
])"
185+
`;
186+
187+
snapshot[`isSetOf<T> > returns properly named function 1`] = `"isSetOf(isNumber)"`;
188+
189+
snapshot[`isSetOf<T> > returns properly named function 2`] = `"isSetOf((anonymous))"`;

is/__snapshots__/utility_test.ts.snap

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

3-
snapshot[`isUnionOf<T> > returns properly named function 1`] = `
4-
"isUnionOf([
5-
isNumber,
6-
isString,
7-
isBoolean
8-
])"
9-
`;
10-
11-
snapshot[`isOmitOf<T, K> > returns properly named function 1`] = `
12-
"isObjectOf({
13-
a: isNumber,
14-
c: isBoolean
15-
})"
16-
`;
17-
18-
snapshot[`isOmitOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
19-
203
snapshot[`isPartialOf<T> > returns properly named function 1`] = `
214
"isObjectOf({
225
a: isOptionalOf(isNumber),
@@ -39,15 +22,6 @@ snapshot[`isPartialOf<T> > returns properly named function 2`] = `
3922
})"
4023
`;
4124
42-
snapshot[`isPickOf<T, K> > returns properly named function 1`] = `
43-
"isObjectOf({
44-
a: isNumber,
45-
c: isBoolean
46-
})"
47-
`;
48-
49-
snapshot[`isPickOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
50-
5125
snapshot[`isRequiredOf<T> > returns properly named function 1`] = `
5226
"isObjectOf({
5327
a: isNumber,
@@ -76,3 +50,29 @@ snapshot[`isIntersectionOf<T> > returns properly named function 1`] = `
7650
b: isString
7751
})"
7852
`;
53+
54+
snapshot[`isPickOf<T, K> > returns properly named function 1`] = `
55+
"isObjectOf({
56+
a: isNumber,
57+
c: isBoolean
58+
})"
59+
`;
60+
61+
snapshot[`isPickOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
62+
63+
snapshot[`isOmitOf<T, K> > returns properly named function 1`] = `
64+
"isObjectOf({
65+
a: isNumber,
66+
c: isBoolean
67+
})"
68+
`;
69+
70+
snapshot[`isOmitOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
71+
72+
snapshot[`isUnionOf<T> > returns properly named function 1`] = `
73+
"isUnionOf([
74+
isNumber,
75+
isString,
76+
isBoolean
77+
])"
78+
`;

is/core.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,9 @@ export function isSet(x: unknown): x is Set<unknown> {
142142
/**
143143
* Return `true` if the type of `x` is `Record<PropertyKey, unknown>`.
144144
*
145+
* Note that this function check if the `x` is an instance of `Object`.
146+
* Use `isRecordLike` instead if you want to check if the `x` satisfies the `Record<PropertyKey, unknown>` type.
147+
*
145148
* ```ts
146149
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
147150
*
@@ -158,6 +161,33 @@ export function isRecord(
158161
return x != null && typeof x === "object" && x.constructor === Object;
159162
}
160163

164+
/**
165+
* Return `true` if the type of `x` is like `Record<PropertyKey, unknown>`.
166+
*
167+
* Note that this function returns `true` for ambiguous instances like `Set`, `Map`, `Date`, `Promise`, etc.
168+
*
169+
* ```ts
170+
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
171+
*
172+
* const a: unknown = {"a": 0, "b": 1};
173+
* if (is.RecordLike(a)) {
174+
* // a is narrowed to Record<PropertyKey, unknown>
175+
* const _: Record<PropertyKey, unknown> = a;
176+
* }
177+
*
178+
* const b: unknown = new Date();
179+
* if (is.RecordLike(b)) {
180+
* // a is narrowed to Record<PropertyKey, unknown>
181+
* const _: Record<PropertyKey, unknown> = b;
182+
* }
183+
* ```
184+
*/
185+
export function isRecordLike(
186+
x: unknown,
187+
): x is Record<PropertyKey, unknown> {
188+
return x != null && !Array.isArray(x) && typeof x === "object";
189+
}
190+
161191
/**
162192
* Return `true` if the type of `x` is `Map<unknown, unknown>`.
163193
*
@@ -345,6 +375,7 @@ export default {
345375
Number: isNumber,
346376
Primitive: isPrimitive,
347377
Record: isRecord,
378+
RecordLike: isRecordLike,
348379
Set: isSet,
349380
String: isString,
350381
Symbol: isSymbol,

is/core_test.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import is, {
1717
isNumber,
1818
isPrimitive,
1919
isRecord,
20+
isRecordLike,
2021
isSet,
2122
isString,
2223
isSymbol,
@@ -147,6 +148,12 @@ Deno.test("isRecord", async (t) => {
147148
});
148149
});
149150

151+
Deno.test("isRecordLike", async (t) => {
152+
await testWithExamples(t, isRecordLike, {
153+
validExamples: ["record", "date", "promise", "set", "map"],
154+
});
155+
});
156+
150157
Deno.test("isMap", async (t) => {
151158
await testWithExamples(t, isMap, {
152159
validExamples: ["map"],

0 commit comments

Comments
 (0)