Skip to content

Commit 2e6d880

Browse files
committed
feat[isObjectOf]: discover symbol properties in predObj
Ref #94, #95
1 parent 0a12716 commit 2e6d880

File tree

3 files changed

+136
-1
lines changed

3 files changed

+136
-1
lines changed

is/__snapshots__/object_of_test.ts.snap

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,19 @@ snapshot[`isObjectOf<T> > returns properly named predicate function 3`] = `
1717
})
1818
})"
1919
`;
20+
21+
snapshot[`isObjectOf<T> > with symbol properties > returns properly named predicate function 1`] = `
22+
"isObjectOf({
23+
a: isNumber,
24+
b: isString,
25+
Symbol(s): isBoolean
26+
})"
27+
`;
28+
29+
snapshot[`isObjectOf<T> > with symbol properties > returns properly named predicate function 2`] = `
30+
"isObjectOf({
31+
Symbol(a): isObjectOf({
32+
Symbol(b): isObjectOf({Symbol(c): isBoolean})
33+
})
34+
})"
35+
`;

is/object_of.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@ export function isObjectOf<
4848
Array.isArray(x)
4949
) return false;
5050
// Check each values
51-
return Object.keys(predObj).every((k) => predObj[k]((x as T)[k]));
51+
return [
52+
...Object.keys(predObj),
53+
...Object.getOwnPropertySymbols(predObj),
54+
].every((k) => predObj[k]((x as T)[k]));
5255
},
5356
"isObjectOf",
5457
predObj,

is/object_of_test.ts

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,120 @@ Deno.test("isObjectOf<T>", async (t) => {
152152
});
153153
},
154154
);
155+
156+
await t.step("with symbol properties", async (t) => {
157+
const s = Symbol("s");
158+
const predObj = {
159+
a: is.Number,
160+
b: is.String,
161+
[s]: is.Boolean,
162+
};
163+
164+
await t.step("returns properly named predicate function", async (t) => {
165+
await assertSnapshot(t, isObjectOf(predObj).name);
166+
await assertSnapshot(
167+
t,
168+
isObjectOf({
169+
[Symbol("a")]: isObjectOf({
170+
[Symbol("b")]: isObjectOf({ [Symbol("c")]: is.Boolean }),
171+
}),
172+
}).name,
173+
);
174+
});
175+
176+
await t.step("returns true on T object", () => {
177+
assertEquals(isObjectOf(predObj)({ a: 0, b: "a", [s]: true }), true);
178+
assertEquals(
179+
isObjectOf(predObj)({ a: 0, b: "a", [s]: true, d: "ignored" }),
180+
true,
181+
"Undefined properties are ignored",
182+
);
183+
assertEquals(
184+
isObjectOf(predObj)({
185+
a: 0,
186+
b: "a",
187+
[s]: true,
188+
[Symbol("t")]: "ignored",
189+
}),
190+
true,
191+
"Undefined symbol properties are ignored",
192+
);
193+
assertEquals(
194+
isObjectOf(predObj)(
195+
Object.assign(() => void 0, { a: 0, b: "a", [s]: true }),
196+
),
197+
true,
198+
"Function are treated as an object",
199+
);
200+
});
201+
202+
await t.step("returns false on non T object", () => {
203+
assertEquals(isObjectOf(predObj)("a"), false, "Value is not an object");
204+
assertEquals(
205+
isObjectOf(predObj)({ a: 0, b: "a", [s]: "" }),
206+
false,
207+
"Object have a different type symbol property",
208+
);
209+
assertEquals(
210+
isObjectOf(predObj)({ a: 0, b: "a" }),
211+
false,
212+
"Object does not have symbol property",
213+
);
214+
const arrayWithSymbolProp = ["ignored"];
215+
// deno-lint-ignore no-explicit-any
216+
(arrayWithSymbolProp as any)[s] = true;
217+
assertEquals(
218+
isObjectOf({ [s]: is.Boolean })(arrayWithSymbolProp),
219+
false,
220+
"Value is not an object",
221+
);
222+
});
223+
224+
await t.step("predicated type is correct", () => {
225+
const a = Symbol("a");
226+
const b = Symbol("b");
227+
const c = Symbol("c");
228+
const d = Symbol("d");
229+
const e = Symbol("e");
230+
const f = Symbol("f");
231+
const predObj2 = {
232+
[a]: as.Readonly(as.Optional(is.String)),
233+
[b]: as.Optional(as.Readonly(is.String)),
234+
[c]: as.Readonly(is.String),
235+
[d]: as.Optional(is.String),
236+
[e]: as.Unreadonly(as.Unoptional(as.Readonly(as.Optional(is.String)))),
237+
[f]: as.Unoptional(as.Unreadonly(as.Optional(as.Readonly(is.String)))),
238+
};
239+
const x: unknown = {};
240+
241+
if (isObjectOf(predObj)(x)) {
242+
assertType<
243+
Equal<
244+
typeof x,
245+
{
246+
a: number;
247+
b: string;
248+
[s]: boolean;
249+
}
250+
>
251+
>(true);
252+
}
253+
254+
if (isObjectOf(predObj2)(x)) {
255+
assertType<
256+
Equal<
257+
typeof x,
258+
{
259+
readonly [a]?: string;
260+
readonly [b]?: string;
261+
readonly [c]: string;
262+
[d]?: string;
263+
[e]: string;
264+
[f]: string;
265+
}
266+
>
267+
>(true);
268+
}
269+
});
270+
});
155271
});

0 commit comments

Comments
 (0)