Skip to content

Commit

Permalink
feat[isRequiredOf]: discover symbol properties in pred.predObj
Browse files Browse the repository at this point in the history
  • Loading branch information
Milly committed Aug 8, 2024
1 parent ae13e2f commit 4ec8855
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 3 deletions.
24 changes: 24 additions & 0 deletions is/__snapshots__/required_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ snapshot[`isRequiredOf<T> > returns properly named predicate function 2`] = `
d: asReadonly(isString)
})"
`;
snapshot[`isRequiredOf<T> > with symbol properties > returns properly named predicate function 1`] = `
"isObjectOf({
a: isNumber,
Symbol(b): isUnionOf([
isString,
isUndefined
]),
Symbol(c): isBoolean,
Symbol(d): asReadonly(isString)
})"
`;
snapshot[`isRequiredOf<T> > with symbol properties > returns properly named predicate function 2`] = `
"isObjectOf({
a: isNumber,
Symbol(b): isUnionOf([
isString,
isUndefined
]),
Symbol(c): isBoolean,
Symbol(d): asReadonly(isString)
})"
`;
11 changes: 8 additions & 3 deletions is/required_of.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,14 @@ export function isRequiredOf<
):
& Predicate<FlatType<Required<T>>>
& IsPredObj<P> {
const predObj = Object.fromEntries(
Object.entries(pred.predObj).map(([k, v]) => [k, asUnoptional(v)]),
);
const keys = [
...Object.keys(pred.predObj),
...Object.getOwnPropertySymbols(pred.predObj),
];
const predObj: Record<PropertyKey, Predicate<unknown>> = { ...pred.predObj };
for (const key of keys) {
predObj[key] = asUnoptional(predObj[key]);
}
return isObjectOf(predObj) as
& Predicate<FlatType<Required<T>>>
& IsPredObj<P>;
Expand Down
55 changes: 55 additions & 0 deletions is/required_of_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,59 @@ Deno.test("isRequiredOf<T>", async (t) => {
>(true);
}
});

await t.step("with symbol properties", async (t) => {
const b = Symbol("b");
const c = Symbol("c");
const d = Symbol("d");
const pred = is.ObjectOf({
a: is.Number,
[b]: is.UnionOf([is.String, is.Undefined]),
[c]: as.Optional(is.Boolean),
[d]: as.Readonly(is.String),
});
await t.step("returns properly named predicate function", async (t) => {
await assertSnapshot(t, isRequiredOf(pred).name);
await assertSnapshot(t, isRequiredOf(isRequiredOf(pred)).name);
});

await t.step("returns true on Required<T> object", () => {
assertEquals(
isRequiredOf(pred)({ a: undefined, [b]: undefined, [c]: undefined }),
false,
"Object does not have required properties",
);
assertEquals(
isRequiredOf(pred)({}),
false,
"Object does not have required properties",
);
});

await t.step("returns false on non Required<T> object", () => {
assertEquals(isRequiredOf(pred)("a"), false, "Value is not an object");
assertEquals(
isRequiredOf(pred)({ a: 0, [b]: "a", [c]: "" }),
false,
"Object have a different type property",
);
});

await t.step("predicated type is correct", () => {
const a: unknown = { a: 0, [b]: "a", [c]: true };
if (isRequiredOf(pred)(a)) {
assertType<
Equal<
typeof a,
{
a: number;
[b]: string | undefined;
[c]: boolean;
readonly [d]: string;
}
>
>(true);
}
});
});
});

0 comments on commit 4ec8855

Please sign in to comment.