Skip to content

Commit

Permalink
👍 Add isReadonlyOf and deprecate `isReadonlyTupleOf/isReadonlyUnifo…
Browse files Browse the repository at this point in the history
…rmTupleOf`
  • Loading branch information
lambdalisue committed Feb 12, 2024
1 parent 5d5411f commit 40f5c8a
Show file tree
Hide file tree
Showing 6 changed files with 258 additions and 150 deletions.
18 changes: 18 additions & 0 deletions is/__snapshots__/annotation_test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
export const snapshot = {};

snapshot[`isReadonlyOf<T> > returns properly named function 1`] = `
"isReadonlyOf(isTupleOf([
isString,
isNumber,
isBoolean
]))"
`;
snapshot[`isReadonlyOf<T> > returns properly named function 2`] = `"isReadonlyOf(isUniformTupleOf(3, isString))"`;
snapshot[`isReadonlyOf<T> > returns properly named function 3`] = `
"isReadonlyOf(isObjectOf({
a: isString,
b: isNumber,
c: isBoolean
}))"
`;
snapshot[`isOptionalOf<T> > returns properly named function 1`] = `"isOptionalOf(isNumber)"`;
snapshot[`isOptionalOf<T> > returns properly named function 2`] = `"isOptionalOf(isNumber)"`;
176 changes: 88 additions & 88 deletions is/__snapshots__/factory_test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
export const snapshot = {};

snapshot[`isSetOf<T> > returns properly named function 1`] = `"isSetOf(isNumber)"`;
snapshot[`isSetOf<T> > returns properly named function 2`] = `"isSetOf((anonymous))"`;
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
snapshot[`isMapOf<T> > returns properly named function 1`] = `"isMapOf(isNumber, undefined)"`;
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber, undefined)"`;
snapshot[`isMapOf<T> > returns properly named function 2`] = `"isMapOf((anonymous), undefined)"`;
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous), undefined)"`;
snapshot[`isTupleOf<T> > returns properly named function 1`] = `
"isTupleOf([
Expand All @@ -34,36 +26,14 @@ snapshot[`isTupleOf<T> > returns properly named function 3`] = `
])"
`;
snapshot[`isMapOf<T, K> > returns properly named function 1`] = `"isMapOf(isNumber, isString)"`;
snapshot[`isMapOf<T, K> > returns properly named function 2`] = `"isMapOf((anonymous), isString)"`;
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
"isTupleOf([
isNumber,
isString,
isBoolean
], isArray)"
`;
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
"isTupleOf([
isTupleOf([
isTupleOf([
isNumber,
isString,
isBoolean
], isArray)
], isArray)
])"
`;
snapshot[`isArrayOf<T> > returns properly named function 1`] = `"isArrayOf(isNumber)"`;
snapshot[`isArrayOf<T> > returns properly named function 2`] = `"isArrayOf((anonymous))"`;
snapshot[`isInstanceOf<T> > returns properly named function 1`] = `"isInstanceOf(Date)"`;
snapshot[`isInstanceOf<T> > returns properly named function 2`] = `"isInstanceOf((anonymous))"`;
snapshot[`isLiteralOf<T> > returns properly named function 1`] = `'isLiteralOf("hello")'`;
snapshot[`isLiteralOf<T> > returns properly named function 2`] = `"isLiteralOf(100)"`;
Expand All @@ -78,8 +48,58 @@ snapshot[`isLiteralOf<T> > returns properly named function 6`] = `"isLiteralOf(u
snapshot[`isLiteralOf<T> > returns properly named function 7`] = `"isLiteralOf(Symbol(asdf))"`;
snapshot[`isObjectOf<T> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
b: isString,
c: isBoolean
})"
`;
snapshot[`isObjectOf<T> > returns properly named function 2`] = `"isObjectOf({a: a})"`;
snapshot[`isObjectOf<T> > returns properly named function 3`] = `
"isObjectOf({
a: isObjectOf({
b: isObjectOf({c: isBoolean})
})
})"
`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
"isReadonlyOf(isTupleOf([
isNumber,
isString,
isBoolean
]))"
`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isTupleOf([(anonymous)]))"`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
"isReadonlyOf(isTupleOf([
isReadonlyOf(isTupleOf([
isReadonlyOf(isTupleOf([
isNumber,
isString,
isBoolean
]))
]))
]))"
`;
snapshot[`isSetOf<T> > returns properly named function 1`] = `"isSetOf(isNumber)"`;
snapshot[`isSetOf<T> > returns properly named function 2`] = `"isSetOf((anonymous))"`;
snapshot[`isLiteralOneOf<T> > returns properly named function 1`] = `'isLiteralOneOf(["hello", "world"])'`;
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
snapshot[`isStrictOf<T> > returns properly named function 1`] = `
"isStrictOf(isObjectOf({
a: isNumber,
Expand All @@ -98,84 +118,64 @@ snapshot[`isStrictOf<T> > returns properly named function 3`] = `
}))"
`;
snapshot[`isMapOf<T, K> > returns properly named function 1`] = `"isMapOf(isNumber, isString)"`;
snapshot[`isMapOf<T, K> > returns properly named function 2`] = `"isMapOf((anonymous), isString)"`;
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 1`] = `
"isReadonlyTupleOf([
"isReadonlyOf(isTupleOf([
isNumber,
isString,
isBoolean
], isArray)"
], isArray))"
`;
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 2`] = `"isReadonlyTupleOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 2`] = `"isReadonlyOf(isTupleOf([(anonymous)], isArrayOf(isString)))"`;
snapshot[`isReadonlyTupleOf<T, E> > returns properly named function 3`] = `
"isReadonlyTupleOf([
isReadonlyTupleOf([
isReadonlyTupleOf([
"isReadonlyOf(isTupleOf([
isReadonlyOf(isTupleOf([
isReadonlyOf(isTupleOf([
isNumber,
isString,
isBoolean
], isArray)
], isArray)
], isArray)"
], isArray))
], isArray))
], isArray))"
`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyUniformTupleOf(3, isAny)"`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 1`] = `"isReadonlyOf(isUniformTupleOf(3, isAny))"`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyUniformTupleOf(3, isNumber)"`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 2`] = `"isReadonlyOf(isUniformTupleOf(3, isNumber))"`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyUniformTupleOf(3, (anonymous))"`;
snapshot[`isReadonlyUniformTupleOf<T> > returns properly named function 3`] = `"isReadonlyOf(isUniformTupleOf(3, (anonymous)))"`;
snapshot[`isRecordOf<T, K> > returns properly named function 1`] = `"isRecordOf(isNumber, isString)"`;
snapshot[`isMapOf<T> > returns properly named function 1`] = `"isMapOf(isNumber, undefined)"`;
snapshot[`isRecordOf<T, K> > returns properly named function 2`] = `"isRecordOf((anonymous), isString)"`;
snapshot[`isMapOf<T> > returns properly named function 2`] = `"isMapOf((anonymous), undefined)"`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 1`] = `
"isReadonlyTupleOf([
snapshot[`isTupleOf<T, E> > returns properly named function 1`] = `
"isTupleOf([
isNumber,
isString,
isBoolean
])"
], isArray)"
`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 2`] = `"isReadonlyTupleOf([(anonymous)])"`;
snapshot[`isTupleOf<T, E> > returns properly named function 2`] = `"isTupleOf([(anonymous)], isArrayOf(isString))"`;
snapshot[`isReadonlyTupleOf<T> > returns properly named function 3`] = `
"isReadonlyTupleOf([
isReadonlyTupleOf([
isReadonlyTupleOf([
snapshot[`isTupleOf<T, E> > returns properly named function 3`] = `
"isTupleOf([
isTupleOf([
isTupleOf([
isNumber,
isString,
isBoolean
])
])
], isArray)
], isArray)
])"
`;
snapshot[`isRecordOf<T> > returns properly named function 1`] = `"isRecordOf(isNumber, undefined)"`;
snapshot[`isRecordOf<T> > returns properly named function 2`] = `"isRecordOf((anonymous), undefined)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 1`] = `"isUniformTupleOf(3, isAny)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 2`] = `"isUniformTupleOf(3, isNumber)"`;
snapshot[`isUniformTupleOf<T> > returns properly named function 3`] = `"isUniformTupleOf(3, (anonymous))"`;
snapshot[`isObjectOf<T> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
b: isString,
c: isBoolean
})"
`;
snapshot[`isObjectOf<T> > returns properly named function 2`] = `"isObjectOf({a: a})"`;
snapshot[`isObjectOf<T> > returns properly named function 3`] = `
"isObjectOf({
a: isObjectOf({
b: isObjectOf({c: isBoolean})
})
})"
`;
36 changes: 18 additions & 18 deletions is/__snapshots__/utility_test.ts.snap
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
export const snapshot = {};

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

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

snapshot[`isUnionOf<T> > returns properly named function 1`] = `
"isUnionOf([
isNumber,
Expand All @@ -8,6 +17,15 @@ snapshot[`isUnionOf<T> > returns properly named function 1`] = `
])"
`;
snapshot[`isPickOf<T, K> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
c: isBoolean
})"
`;
snapshot[`isPickOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
snapshot[`isPartialOf<T> > returns properly named function 1`] = `
"isObjectOf({
a: isOptionalOf(isNumber),
Expand All @@ -24,27 +42,9 @@ snapshot[`isPartialOf<T> > returns properly named function 2`] = `
})"
`;
snapshot[`isOmitOf<T, K> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
c: isBoolean
})"
`;
snapshot[`isOmitOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
snapshot[`isIntersectionOf<T> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
b: isString
})"
`;
snapshot[`isPickOf<T, K> > returns properly named function 1`] = `
"isObjectOf({
a: isNumber,
c: isBoolean
})"
`;
snapshot[`isPickOf<T, K> > returns properly named function 2`] = `"isObjectOf({a: isNumber})"`;
69 changes: 69 additions & 0 deletions is/annotation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,76 @@ type IsOptionalOfMetadata = {
args: Parameters<typeof isOptionalOf>;
};

/**
* Return `true` if the type of predicate `x` is `Readonly` predicate.
*
* ```ts
* import { is, type Predicate, type WithReadonly } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
*
* const pred: Predicate<unknown> = is.ReadonlyOf(is.Unknown);
* if (is.Readonly(pred)) {
* // a is narrowed to Predicate<unknown> & WithReadonly
* const _: Predicate<unknown> & WithReadonly = pred;
* }
* ```
*/
export function isReadonly<P extends Predicate<unknown>>(
x: P,

Check warning on line 89 in is/annotation.ts

View check run for this annotation

Codecov / codecov/patch

is/annotation.ts#L87-L89

Added lines #L87 - L89 were not covered by tests
): x is P & WithReadonly {
return (x as Partial<WithReadonly>).readonly === true;
}

Check warning on line 92 in is/annotation.ts

View check run for this annotation

Codecov / codecov/patch

is/annotation.ts#L91-L92

Added lines #L91 - L92 were not covered by tests

/**
* Annotate the type predicate function as `Readonly`.
*/
export type WithReadonly = {
readonly: true;
};

/**
* Return an `Readonly` annotated type predicate function that returns `true` if the type of `x` is `T`.
*
* Note that the predicate function returned from this factory does nothing but annotate the types.
*
* To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
*
* ```ts
* import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
*
* const isMyType = is.ReadonlyOf(is.String);
* const a: unknown = "a";
* if (isMyType(a)) {
* // a is narrowed to string | undefined
* const _: string | undefined = a;
* }
* ```
*/
export function isReadonlyOf<T>(
pred: Predicate<T>,
):
& Predicate<Readonly<T>>
& WithReadonly
& WithMetadata<IsReadonlyOfMetadata> {
return Object.defineProperties(
setPredicateFactoryMetadata(
(x: unknown): x is Readonly<T> => pred(x),
{ name: "isReadonlyOf", args: [pred] },
),
{ readonly: { value: true as const } },
) as
& Predicate<Readonly<T>>
& WithReadonly
& WithMetadata<IsReadonlyOfMetadata>;
}

type IsReadonlyOfMetadata = {
name: "isReadonlyOf";
args: Parameters<typeof isReadonlyOf>;
};

export default {
Optional: isOptional,
OptionalOf: isOptionalOf,
Readonly: isReadonly,
ReadonlyOf: isReadonlyOf,
};
Loading

0 comments on commit 40f5c8a

Please sign in to comment.