Skip to content

Commit 1848cb6

Browse files
committed
feat[isPickOf]: copy symbol properties from pred.predObj
1 parent b9ec2c0 commit 1848cb6

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

is/__snapshots__/pick_of_test.ts.snap

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,12 @@ snapshot[`isPickOf<T, K> > returns properly named predicate function 1`] = `
88
`;
99

1010
snapshot[`isPickOf<T, K> > returns properly named predicate function 2`] = `"isObjectOf({a: isNumber})"`;
11+
12+
snapshot[`isPickOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `
13+
"isObjectOf({
14+
a: isNumber,
15+
Symbol(c): isBoolean
16+
})"
17+
`;
18+
19+
snapshot[`isPickOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isObjectOf({Symbol(c): isBoolean})"`;

is/pick_of.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,15 @@ export function isPickOf<
4343
):
4444
& Predicate<FlatType<Pick<T, K>>>
4545
& IsPredObj<P> {
46-
const s = new Set(keys);
47-
const predObj = Object.fromEntries(
48-
Object.entries(pred.predObj).filter(([k]) => s.has(k as K)),
49-
);
50-
return isObjectOf(predObj) as
46+
const omitKeys = new Set([
47+
...Object.keys(pred.predObj),
48+
...Object.getOwnPropertySymbols(pred.predObj),
49+
]).difference(new Set(keys));
50+
const predObj = { ...pred.predObj };
51+
for (const key of omitKeys) {
52+
delete predObj[key];
53+
}
54+
return isObjectOf(predObj as Record<PropertyKey, Predicate<unknown>>) as
5155
& Predicate<FlatType<Pick<T, K>>>
5256
& IsPredObj<P>;
5357
}

is/pick_of_test.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,54 @@ Deno.test("isPickOf<T, K>", async (t) => {
5151
>(true);
5252
}
5353
});
54+
55+
await t.step("with symbol properties", async (t) => {
56+
const b = Symbol("b");
57+
const c = Symbol("c");
58+
const pred = is.ObjectOf({
59+
a: is.Number,
60+
[b]: is.String,
61+
[c]: is.Boolean,
62+
});
63+
64+
await t.step("returns properly named predicate function", async (t) => {
65+
await assertSnapshot(t, isPickOf(pred, ["a", c]).name);
66+
await assertSnapshot(t, isPickOf(isPickOf(pred, ["a", c]), [c]).name);
67+
});
68+
69+
await t.step("returns true on Pick<T, K> object", () => {
70+
assertEquals(
71+
isPickOf(pred, ["a", c])({ a: 0, [b]: undefined, [c]: true }),
72+
true,
73+
);
74+
assertEquals(isPickOf(pred, ["a"])({ a: 0 }), true);
75+
});
76+
77+
await t.step("returns false on non Pick<T, K> object", () => {
78+
assertEquals(
79+
isPickOf(pred, ["a", c])("a"),
80+
false,
81+
"Value is not an object",
82+
);
83+
assertEquals(
84+
isPickOf(pred, ["a", c])({ a: 0, [b]: "a", [c]: "" }),
85+
false,
86+
"Object have a different type property",
87+
);
88+
});
89+
90+
await t.step("predicated type is correct", () => {
91+
const a: unknown = { a: 0, [b]: "a", [c]: true };
92+
if (isPickOf(pred, ["a", c])(a)) {
93+
assertType<
94+
Equal<typeof a, { a: number; [c]: boolean }>
95+
>(true);
96+
}
97+
if (isPickOf(isPickOf(pred, ["a", c]), ["a"])(a)) {
98+
assertType<
99+
Equal<typeof a, { a: number }>
100+
>(true);
101+
}
102+
});
103+
});
54104
});

0 commit comments

Comments
 (0)