Skip to content

Commit 69bd020

Browse files
committed
feat[isRecordObjectOf]: checks own symbol key properties
1 parent d3cc366 commit 69bd020

File tree

3 files changed

+76
-1
lines changed

3 files changed

+76
-1
lines changed

is/__snapshots__/record_object_of_test.ts.snap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ snapshot[`isRecordObjectOf<T> > returns properly named predicate function 2`] =
77
snapshot[`isRecordObjectOf<T, K> > returns properly named predicate function 1`] = `"isRecordObjectOf(isNumber, isString)"`;
88
99
snapshot[`isRecordObjectOf<T, K> > returns properly named predicate function 2`] = `"isRecordObjectOf((anonymous), isString)"`;
10+
11+
snapshot[`isRecordObjectOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `"isRecordObjectOf(isNumber, isSymbol)"`;
12+
13+
snapshot[`isRecordObjectOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isRecordObjectOf((anonymous), isSymbol)"`;

is/record_object_of.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,10 @@ export function isRecordObjectOf<T, K extends PropertyKey = PropertyKey>(
3939
return rewriteName(
4040
(x: unknown): x is Record<K, T> => {
4141
if (!isRecordObject(x)) return false;
42-
const keys = Object.keys(x);
42+
const keys = [
43+
...Object.keys(x),
44+
...Object.getOwnPropertySymbols(x),
45+
];
4346
for (const k of keys) {
4447
if (!pred(x[k])) return false;
4548
if (predKey && !predKey(k)) return false;

is/record_object_of_test.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,21 @@ Deno.test("isRecordObjectOf<T>", async (t) => {
5252
);
5353
});
5454
});
55+
56+
await t.step("with symbol properties", async (t) => {
57+
const a = Symbol("a");
58+
await t.step("returns true on T record", () => {
59+
assertEquals(isRecordObjectOf(is.Number)({ [a]: 0 }), true);
60+
assertEquals(isRecordObjectOf(is.String)({ [a]: "a" }), true);
61+
assertEquals(isRecordObjectOf(is.Boolean)({ [a]: true }), true);
62+
});
63+
64+
await t.step("returns false on non T record", () => {
65+
assertEquals(isRecordObjectOf(is.String)({ [a]: 0 }), false);
66+
assertEquals(isRecordObjectOf(is.Number)({ [a]: "a" }), false);
67+
assertEquals(isRecordObjectOf(is.String)({ [a]: true }), false);
68+
});
69+
});
5570
});
5671

5772
Deno.test("isRecordObjectOf<T, K>", async (t) => {
@@ -89,6 +104,7 @@ Deno.test("isRecordObjectOf<T, K>", async (t) => {
89104
});
90105

91106
await t.step("checks only object's own properties", async (t) => {
107+
const s = Symbol("s");
92108
await t.step("returns true on T record", () => {
93109
assertEquals(
94110
isRecordObjectOf(is.Number, is.String)(
@@ -115,6 +131,58 @@ Deno.test("isRecordObjectOf<T, K>", async (t) => {
115131
true,
116132
"No own properties",
117133
);
134+
assertEquals(
135+
isRecordObjectOf(is.String, is.String)(
136+
Object.assign(Object.create({ [s]: "ignore" }), {/* empty */}),
137+
),
138+
true,
139+
"No own properties",
140+
);
141+
});
142+
});
143+
144+
await t.step("with symbol properties", async (t) => {
145+
const a = Symbol("a");
146+
await t.step("returns properly named predicate function", async (t) => {
147+
await assertSnapshot(t, isRecordObjectOf(is.Number, is.Symbol).name);
148+
await assertSnapshot(
149+
t,
150+
isRecordObjectOf((_x): _x is string => false, is.Symbol).name,
151+
);
152+
});
153+
154+
await t.step("returns true on T record", () => {
155+
assertEquals(isRecordObjectOf(is.Number, is.Symbol)({ [a]: 0 }), true);
156+
assertEquals(isRecordObjectOf(is.String, is.Symbol)({ [a]: "a" }), true);
157+
assertEquals(
158+
isRecordObjectOf(is.Boolean, is.Symbol)({ [a]: true }),
159+
true,
160+
);
161+
});
162+
163+
await t.step("returns false on non T record", () => {
164+
assertEquals(isRecordObjectOf(is.String, is.Symbol)({ [a]: 0 }), false);
165+
assertEquals(isRecordObjectOf(is.Number, is.Symbol)({ [a]: "a" }), false);
166+
assertEquals(
167+
isRecordObjectOf(is.String, is.Symbol)({ [a]: true }),
168+
false,
169+
);
170+
});
171+
172+
await t.step("returns false on non K record", () => {
173+
assertEquals(isRecordObjectOf(is.Number, is.String)({ [a]: 0 }), false);
174+
assertEquals(isRecordObjectOf(is.String, is.String)({ [a]: "a" }), false);
175+
assertEquals(
176+
isRecordObjectOf(is.Boolean, is.String)({ [a]: true }),
177+
false,
178+
);
179+
});
180+
181+
await t.step("predicated type is correct", () => {
182+
const a: unknown = { a: 0 };
183+
if (isRecordObjectOf(is.Number, is.Symbol)(a)) {
184+
assertType<Equal<typeof a, Record<symbol, number>>>(true);
185+
}
118186
});
119187
});
120188
});

0 commit comments

Comments
 (0)