Skip to content

Commit

Permalink
Merge pull request #97 from jsr-core/symbol-properties-wip
Browse files Browse the repository at this point in the history
feat[is]: `is*` functions allows symbol properties
  • Loading branch information
lambdalisue authored Aug 11, 2024
2 parents e9fd92e + 4a5dc04 commit 123572a
Show file tree
Hide file tree
Showing 38 changed files with 1,086 additions and 87 deletions.
18 changes: 18 additions & 0 deletions __snapshots__/_inspect_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ snapshot[`inspect > record 3`] = `

snapshot[`inspect > record 4`] = `"{a: {b: {c: 0}}}"`;

snapshot[`inspect > record 5`] = `"{Symbol(a): 0}"`;

snapshot[`inspect > record 6`] = `
"{
a: 0,
c: true,
Symbol(b): 1
}"
`;

snapshot[`inspect > record 7`] = `
"{
Symbol(a): {
Symbol(b): {Symbol(c): 0}
}
}"
`;

snapshot[`inspect > function 1`] = `"inspect"`;

snapshot[`inspect > function 2`] = `"(anonymous)"`;
Expand Down
5 changes: 2 additions & 3 deletions _inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,8 @@ function inspectRecord(
options: InspectOptions,
): string {
const { threshold = defaultThreshold } = options;
const vs = Object.entries(value).map(([k, v]) =>
`${k}: ${inspect(v, options)}`
);
const vs = [...Object.keys(value), ...Object.getOwnPropertySymbols(value)]
.map((k) => `${k.toString()}: ${inspect(value[k], options)}`);
const s = vs.join(", ");
if (s.length <= threshold) return `{${s}}`;
const m = vs.join(",\n");
Expand Down
6 changes: 6 additions & 0 deletions _inspect_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,12 @@ Deno.test("inspect", async (t) => {
await assertSnapshot(t, inspect({ a: 0, b: 1, c: 2 }));
await assertSnapshot(t, inspect({ a: "a", b: 1, c: true }));
await assertSnapshot(t, inspect({ a: { b: { c: 0 } } }));
await assertSnapshot(t, inspect({ [Symbol("a")]: 0 }));
await assertSnapshot(t, inspect({ a: 0, [Symbol("b")]: 1, c: true }));
await assertSnapshot(
t,
inspect({ [Symbol("a")]: { [Symbol("b")]: { [Symbol("c")]: 0 } } }),
);
});
await t.step("function", async (t) => {
await assertSnapshot(t, inspect(inspect));
Expand Down
16 changes: 16 additions & 0 deletions is/__snapshots__/intersection_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,19 @@ snapshot[`isIntersectionOf<T> > returns properly named predicate function 3`] =
isObjectOf({b: isString})
])"
`;
snapshot[`isIntersectionOf<T> > with symbol properties > returns properly named predicate function 1`] = `"isString"`;
snapshot[`isIntersectionOf<T> > with symbol properties > returns properly named predicate function 2`] = `
"isObjectOf({
a: isNumber,
Symbol(b): isString
})"
`;
snapshot[`isIntersectionOf<T> > with symbol properties > returns properly named predicate function 3`] = `
"isIntersectionOf([
isFunction,
isObjectOf({Symbol(b): isString})
])"
`;
16 changes: 16 additions & 0 deletions is/__snapshots__/object_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,19 @@ snapshot[`isObjectOf<T> > returns properly named predicate function 3`] = `
})
})"
`;
snapshot[`isObjectOf<T> > with symbol properties > returns properly named predicate function 1`] = `
"isObjectOf({
a: isNumber,
b: isString,
Symbol(s): isBoolean
})"
`;
snapshot[`isObjectOf<T> > with symbol properties > returns properly named predicate function 2`] = `
"isObjectOf({
Symbol(a): isObjectOf({
Symbol(b): isObjectOf({Symbol(c): isBoolean})
})
})"
`;
9 changes: 9 additions & 0 deletions is/__snapshots__/omit_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ snapshot[`isOmitOf<T, K> > returns properly named predicate function 1`] = `
`;

snapshot[`isOmitOf<T, K> > returns properly named predicate function 2`] = `"isObjectOf({a: isNumber})"`;

snapshot[`isOmitOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `
"isObjectOf({
a: isNumber,
Symbol(c): isBoolean
})"
`;

snapshot[`isOmitOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isObjectOf({a: isNumber})"`;
8 changes: 4 additions & 4 deletions is/__snapshots__/parameters_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,19 @@ snapshot[`isParametersOf<T> > returns properly named predicate function 4`] = `
])"
`;
snapshot[`isParametersOf<T, E> > returns properly named predicate function 1`] = `
snapshot[`isParametersOf<T, R> > returns properly named predicate function 1`] = `
"isParametersOf([
isNumber,
isString,
asOptional(isBoolean)
], isArray)"
`;
snapshot[`isParametersOf<T, E> > returns properly named predicate function 2`] = `"isParametersOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isParametersOf<T, R> > returns properly named predicate function 2`] = `"isParametersOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isParametersOf<T, E> > returns properly named predicate function 3`] = `"isParametersOf([], isArrayOf(isString))"`;
snapshot[`isParametersOf<T, R> > returns properly named predicate function 3`] = `"isParametersOf([], isArrayOf(isString))"`;
snapshot[`isParametersOf<T, E> > returns properly named predicate function 4`] = `
snapshot[`isParametersOf<T, R> > returns properly named predicate function 4`] = `
"isParametersOf([
isParametersOf([
isParametersOf([
Expand Down
24 changes: 24 additions & 0 deletions is/__snapshots__/partial_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,27 @@ snapshot[`isPartialOf<T> > returns properly named predicate function 2`] = `
d: asOptional(asReadonly(isString))
})"
`;
snapshot[`isPartialOf<T> > with symbol properties > returns properly named predicate function 1`] = `
"isObjectOf({
a: asOptional(isNumber),
Symbol(b): asOptional(isUnionOf([
isString,
isUndefined
])),
Symbol(c): asOptional(isBoolean),
Symbol(c): asOptional(asReadonly(isString))
})"
`;
snapshot[`isPartialOf<T> > with symbol properties > returns properly named predicate function 2`] = `
"isObjectOf({
a: asOptional(isNumber),
Symbol(b): asOptional(isUnionOf([
isString,
isUndefined
])),
Symbol(c): asOptional(isBoolean),
Symbol(c): asOptional(asReadonly(isString))
})"
`;
9 changes: 9 additions & 0 deletions is/__snapshots__/pick_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,12 @@ snapshot[`isPickOf<T, K> > returns properly named predicate function 1`] = `
`;

snapshot[`isPickOf<T, K> > returns properly named predicate function 2`] = `"isObjectOf({a: isNumber})"`;

snapshot[`isPickOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `
"isObjectOf({
a: isNumber,
Symbol(c): isBoolean
})"
`;

snapshot[`isPickOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isObjectOf({Symbol(c): isBoolean})"`;
22 changes: 22 additions & 0 deletions is/__snapshots__/readonly_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -45,3 +45,25 @@ snapshot[`isReadonlyOf<T> > with isTupleOf > returns properly named predicate fu
snapshot[`isReadonlyOf<T> > with isUniformTupleOf > returns properly named predicate function 1`] = `"isReadonlyOf(isUniformTupleOf(3, isNumber))"`;
snapshot[`isReadonlyOf<T> > with isUniformTupleOf > returns properly named predicate function 2`] = `"isReadonlyOf(isUniformTupleOf(3, isNumber))"`;
snapshot[`isReadonlyOf<T> > with symbol properties > with isObjectOf > returns properly named predicate function 1`] = `
"isReadonlyOf(isObjectOf({
a: isNumber,
Symbol(b): isUnionOf([
isString,
isUndefined
]),
Symbol(c): asReadonly(isBoolean)
}))"
`;
snapshot[`isReadonlyOf<T> > with symbol properties > with isObjectOf > returns properly named predicate function 2`] = `
"isReadonlyOf(isObjectOf({
a: isNumber,
Symbol(b): isUnionOf([
isString,
isUndefined
]),
Symbol(c): asReadonly(isBoolean)
}))"
`;
4 changes: 4 additions & 0 deletions is/__snapshots__/record_object_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ snapshot[`isRecordObjectOf<T> > returns properly named predicate function 2`] =
snapshot[`isRecordObjectOf<T, K> > returns properly named predicate function 1`] = `"isRecordObjectOf(isNumber, isString)"`;
snapshot[`isRecordObjectOf<T, K> > returns properly named predicate function 2`] = `"isRecordObjectOf((anonymous), isString)"`;
snapshot[`isRecordObjectOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `"isRecordObjectOf(isNumber, isSymbol)"`;
snapshot[`isRecordObjectOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isRecordObjectOf((anonymous), isSymbol)"`;
4 changes: 4 additions & 0 deletions is/__snapshots__/record_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,7 @@ snapshot[`isRecordOf<T> > returns properly named predicate function 2`] = `"isRe
snapshot[`isRecordOf<T, K> > returns properly named predicate function 1`] = `"isRecordOf(isNumber, isString)"`;
snapshot[`isRecordOf<T, K> > returns properly named predicate function 2`] = `"isRecordOf((anonymous), isString)"`;
snapshot[`isRecordOf<T, K> > with symbol properties > returns properly named predicate function 1`] = `"isRecordOf(isNumber, isSymbol)"`;
snapshot[`isRecordOf<T, K> > with symbol properties > returns properly named predicate function 2`] = `"isRecordOf((anonymous), isSymbol)"`;
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)
})"
`;
16 changes: 16 additions & 0 deletions is/__snapshots__/strict_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,19 @@ snapshot[`isStrictOf<T> > returns properly named predicate function 3`] = `
}))
}))"
`;
snapshot[`isStrictOf<T> > with symbol properties > returns properly named predicate function 1`] = `
"isStrictOf(isObjectOf({
a: isNumber,
Symbol(b): isString,
Symbol(c): isBoolean
}))"
`;
snapshot[`isStrictOf<T> > with symbol properties > returns properly named predicate function 2`] = `
"isStrictOf(isObjectOf({
a: isStrictOf(isObjectOf({
Symbol(b): isStrictOf(isObjectOf({Symbol(c): isBoolean}))
}))
}))"
`;
6 changes: 3 additions & 3 deletions is/__snapshots__/tuple_of_test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ snapshot[`isTupleOf<T> > returns properly named predicate function 3`] = `
])"
`;
snapshot[`isTupleOf<T, E> > returns properly named predicate function 1`] = `
snapshot[`isTupleOf<T, R> > returns properly named predicate function 1`] = `
"isTupleOf([
isNumber,
isString,
isBoolean
], isArray)"
`;
snapshot[`isTupleOf<T, E> > returns properly named predicate function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isTupleOf<T, R> > returns properly named predicate function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isTupleOf<T, E> > returns properly named predicate function 3`] = `
snapshot[`isTupleOf<T, R> > returns properly named predicate function 3`] = `
"isTupleOf([
isTupleOf([
isTupleOf([
Expand Down
75 changes: 75 additions & 0 deletions is/intersection_of_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,4 +77,79 @@ Deno.test("isIntersectionOf<T>", async (t) => {
>(true);
}
});

await t.step("with symbol properties", async (t) => {
const b = Symbol("b");
const objPreds = [
is.ObjectOf({ a: is.Number }),
is.ObjectOf({ [b]: is.String }),
] as const;
const mixPreds = [
is.Function,
is.ObjectOf({ [b]: is.String }),
] as const;

await t.step("returns properly named predicate function", async (t) => {
assertEquals(typeof isIntersectionOf([is.String]), "function");
await assertSnapshot(t, isIntersectionOf([is.String]).name);
await assertSnapshot(t, isIntersectionOf(objPreds).name);
await assertSnapshot(t, isIntersectionOf(mixPreds).name);
});

await t.step("returns true on all of T", () => {
const f = Object.assign(() => void 0, { [b]: "a" });
assertEquals(isIntersectionOf([is.String])("a"), true);
assertEquals(isIntersectionOf(objPreds)({ a: 0, [b]: "a" }), true);
assertEquals(isIntersectionOf(mixPreds)(f), true);
});

await t.step("returns false on non of T", () => {
const f = Object.assign(() => void 0, { [b]: "a" });
assertEquals(isIntersectionOf(objPreds)("a"), false);
assertEquals(isIntersectionOf(mixPreds)({ a: 0, [b]: "a" }), false);
assertEquals(isIntersectionOf([is.String])(f), false);
});

await t.step("predicated type is correct", () => {
const a: unknown = undefined;

if (isIntersectionOf([is.String])(a)) {
assertType<Equal<typeof a, string>>(true);
}

if (isIntersectionOf(objPreds)(a)) {
assertType<Equal<typeof a, { a: number } & { [b]: string }>>(true);
}

if (isIntersectionOf(mixPreds)(a)) {
assertType<
Equal<
typeof a,
& ((...args: unknown[]) => unknown)
& { [b]: string }
>
>(true);
}
});

await t.step("predicated type is correct (#68)", () => {
const a: unknown = undefined;
const pred = isIntersectionOf([
is.ObjectOf({ id: is.String }),
is.UnionOf([
is.ObjectOf({ result: is.String }),
is.ObjectOf({ error: is.String }),
]),
]);

if (pred(a)) {
assertType<
Equal<
typeof a,
{ id: string } & ({ result: string } | { error: string })
>
>(true);
}
});
});
});
6 changes: 3 additions & 3 deletions is/mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -455,7 +455,7 @@ export const is: {
* }
* ```
*
* With `predElse`:
* With `predRest` to represent rest parameters:
*
* ```ts
* import { as, is } from "@core/unknownutil";
Expand Down Expand Up @@ -823,7 +823,7 @@ export const is: {
*/
SyncFunction: typeof isSyncFunction;
/**
* Return a type predicate function that returns `true` if the type of `x` is `TupleOf<T>` or `TupleOf<T, E>`.
* Return a type predicate function that returns `true` if the type of `x` is `TupleOf<T>` or `TupleOf<T, R>`.
*
* Use {@linkcode isUniformTupleOf} to check if the type of `x` is a tuple of uniform types.
*
Expand All @@ -839,7 +839,7 @@ export const is: {
* }
* ```
*
* With `predElse`:
* With `predRest` to represent rest elements:
*
* ```ts
* import { is } from "@core/unknownutil";
Expand Down
Loading

0 comments on commit 123572a

Please sign in to comment.