@@ -189,7 +189,7 @@ export function isArrayOf<T>(
189189 * // type A = [string, number];
190190 * ```
191191 */
192- export type TupleOf < T extends readonly Predicate < unknown > [ ] > = {
192+ export type TupleOf < T > = {
193193 - readonly [ P in keyof T ] : T [ P ] extends Predicate < infer U > ? U : never ;
194194} ;
195195
@@ -204,37 +204,33 @@ export type TupleOf<T extends readonly Predicate<unknown>[]> = {
204204 * // type A = readonly [string, number];
205205 * ```
206206 */
207- export type ReadonlyTupleOf < T extends readonly Predicate < unknown > [ ] > = {
207+ export type ReadonlyTupleOf < T > = {
208208 [ P in keyof T ] : T [ P ] extends Predicate < infer U > ? U : never ;
209209} ;
210210
211211/**
212- * Return a type predicate function that returns `true` if the type of `x` is `TupleOf<T>`.
212+ * Return a type predicate function that returns `true` if the type of `x` is `TupleOf<T>` or `TupleOf<T, E>` .
213213 *
214214 * To enhance performance, users are advised to cache the return value of this function and mitigate the creation cost.
215215 *
216216 * ```ts
217217 * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
218218 *
219- * const isMyType = is.TupleOf([is.Number, is.String, is.Boolean] as const );
219+ * const isMyType = is.TupleOf([is.Number, is.String, is.Boolean]);
220220 * const a: unknown = [0, "a", true];
221221 * if (isMyType(a)) {
222222 * // a is narrowed to [number, string, boolean]
223223 * const _: [number, string, boolean] = a;
224224 * }
225225 * ```
226226 *
227- * Note that `predTup` must be `readonly` (`as const`) to infer the type of `a` correctly.
228- * TypeScript won't argues if `predTup` is not `readonly` because of its design limitation.
229- * https://github.com/microsoft/TypeScript/issues/34274#issuecomment-541691353
230- *
231- * It can also be used to check the type of the rest of the tuple like:
227+ * With `predElse`:
232228 *
233229 * ```ts
234230 * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
235231 *
236232 * const isMyType = is.TupleOf(
237- * [is.Number, is.String, is.Boolean] as const ,
233+ * [is.Number, is.String, is.Boolean],
238234 * is.ArrayOf(is.Number),
239235 * );
240236 * const a: unknown = [0, "a", true, 0, 1, 2];
@@ -243,33 +239,44 @@ export type ReadonlyTupleOf<T extends readonly Predicate<unknown>[]> = {
243239 * const _: [number, string, boolean, ...number[]] = a;
244240 * }
245241 * ```
242+ *
243+ * Depending on the version of TypeScript and how values are provided, it may be necessary to add `as const` to the array
244+ * used as `predTup`. If a type error occurs, try adding `as const` as follows:
245+ *
246+ * ```ts
247+ * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
248+ *
249+ * const predTup = [is.Number, is.String, is.Boolean] as const;
250+ * const isMyType = is.TupleOf(predTup);
251+ * const a: unknown = [0, "a", true];
252+ * if (isMyType(a)) {
253+ * // a is narrowed to [number, string, boolean]
254+ * const _: [number, string, boolean] = a;
255+ * }
256+ * ```
246257 */
247258export function isTupleOf <
248- T extends readonly Predicate < unknown > [ ] ,
249- R extends TupleOf < T > ,
259+ T extends readonly [ Predicate < unknown > , ...Predicate < unknown > [ ] ] ,
250260> (
251261 predTup : T ,
252- ) : Predicate < R > ;
262+ ) : Predicate < TupleOf < T > > ;
253263export function isTupleOf <
254- T extends readonly Predicate < unknown > [ ] ,
264+ T extends readonly [ Predicate < unknown > , ... Predicate < unknown > [ ] ] ,
255265 E extends Predicate < unknown [ ] > ,
256- R extends [ ...TupleOf < T > , ...PredicateType < E > ] ,
257266> (
258267 predTup : T ,
259268 predElse : E ,
260- ) : Predicate < R > ;
269+ ) : Predicate < [ ... TupleOf < T > , ... PredicateType < E > ] > ;
261270export function isTupleOf <
262- T extends readonly Predicate < unknown > [ ] ,
271+ T extends readonly [ Predicate < unknown > , ... Predicate < unknown > [ ] ] ,
263272 E extends Predicate < unknown [ ] > ,
264- R1 extends TupleOf < T > ,
265- R2 extends [ ...TupleOf < T > , ...PredicateType < E > ] ,
266273> (
267274 predTup : T ,
268275 predElse ?: E ,
269- ) : Predicate < R1 | R2 > {
276+ ) : Predicate < TupleOf < T > | [ ... TupleOf < T > , ... PredicateType < E > ] > {
270277 if ( ! predElse ) {
271278 return Object . defineProperties (
272- ( x : unknown ) : x is R1 => {
279+ ( x : unknown ) : x is TupleOf < T > => {
273280 if ( ! isArray ( x ) || x . length !== predTup . length ) {
274281 return false ;
275282 }
@@ -283,7 +290,7 @@ export function isTupleOf<
283290 ) ;
284291 } else {
285292 return Object . defineProperties (
286- ( x : unknown ) : x is R2 => {
293+ ( x : unknown ) : x is [ ... TupleOf < T > , ... PredicateType < E > ] => {
287294 if ( ! isArray ( x ) || x . length < predTup . length ) {
288295 return false ;
289296 }
@@ -308,59 +315,69 @@ export function isTupleOf<
308315 * ```ts
309316 * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
310317 *
311- * const isMyType = is.ReadonlyTupleOf([is.Number, is.String, is.Boolean] as const );
318+ * const isMyType = is.ReadonlyTupleOf([is.Number, is.String, is.Boolean]);
312319 * const a: unknown = [0, "a", true];
313320 * if (isMyType(a)) {
314321 * // a is narrowed to readonly [number, string, boolean]
315322 * const _: readonly [number, string, boolean] = a;
316323 * }
317324 * ```
318325 *
319- * Note that `predTup` must be `readonly` (`as const`) to infer the type of `a` correctly.
320- * TypeScript won't argues if `predTup` is not `readonly` because of its design limitation.
321- * https://github.com/microsoft/TypeScript/issues/34274#issuecomment-541691353
322- *
323- * It can also be used to check the type of the rest of the tuple like:
326+ * With `predElse`:
324327 *
325328 * ```ts
326329 * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
327330 *
328331 * const isMyType = is.ReadonlyTupleOf(
329- * [is.Number, is.String, is.Boolean] as const ,
332+ * [is.Number, is.String, is.Boolean],
330333 * is.ArrayOf(is.Number),
331334 * );
332335 * const a: unknown = [0, "a", true, 0, 1, 2];
333336 * if (isMyType(a)) {
334337 * // a is narrowed to readonly [number, string, boolean, ...number[]]
335338 * const _: readonly [number, string, boolean, ...number[]] = a;
336339 * }
340+ * ```
341+ *
342+ * Depending on the version of TypeScript and how values are provided, it may be necessary to add `as const` to the array
343+ * used as `predTup`. If a type error occurs, try adding `as const` as follows:
344+ *
345+ * ```ts
346+ * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
347+ *
348+ * const predTup = [is.Number, is.String, is.Boolean] as const;
349+ * const isMyType = is.ReadonlyTupleOf(predTup);
350+ * const a: unknown = [0, "a", true];
351+ * if (isMyType(a)) {
352+ * // a is narrowed to readonly [number, string, boolean]
353+ * const _: readonly [number, string, boolean] = a;
354+ * }
355+ * ```
337356 */
338357export function isReadonlyTupleOf <
339- T extends readonly Predicate < unknown > [ ] ,
340- R extends ReadonlyTupleOf < T > ,
358+ T extends readonly [ Predicate < unknown > , ...Predicate < unknown > [ ] ] ,
341359> (
342360 predTup : T ,
343- ) : Predicate < R > ;
361+ ) : Predicate < ReadonlyTupleOf < T > > ;
344362export function isReadonlyTupleOf <
345- T extends readonly Predicate < unknown > [ ] ,
363+ T extends readonly [ Predicate < unknown > , ... Predicate < unknown > [ ] ] ,
346364 E extends Predicate < unknown [ ] > ,
347- R extends readonly [ ...ReadonlyTupleOf < T > , ...PredicateType < E > ] ,
348365> (
349366 predTup : T ,
350367 predElse : E ,
351- ) : Predicate < R > ;
368+ ) : Predicate < readonly [ ... ReadonlyTupleOf < T > , ... PredicateType < E > ] > ;
352369export function isReadonlyTupleOf <
353- T extends readonly Predicate < unknown > [ ] ,
370+ T extends readonly [ Predicate < unknown > , ... Predicate < unknown > [ ] ] ,
354371 E extends Predicate < unknown [ ] > ,
355- R1 extends ReadonlyTupleOf < T > ,
356- R2 extends readonly [ ...ReadonlyTupleOf < T > , ...PredicateType < E > ] ,
357372> (
358373 predTup : T ,
359374 predElse ?: E ,
360- ) : Predicate < R1 | R2 > {
375+ ) : Predicate <
376+ ReadonlyTupleOf < T > | readonly [ ...ReadonlyTupleOf < T > , ...PredicateType < E > ]
377+ > {
361378 if ( ! predElse ) {
362379 return Object . defineProperties (
363- isTupleOf ( predTup ) as Predicate < R1 > ,
380+ isTupleOf ( predTup ) as Predicate < ReadonlyTupleOf < T > > ,
364381 {
365382 name : {
366383 get : ( ) => `isReadonlyTupleOf(${ inspect ( predTup ) } )` ,
@@ -369,7 +386,9 @@ export function isReadonlyTupleOf<
369386 ) ;
370387 } else {
371388 return Object . defineProperties (
372- isTupleOf ( predTup , predElse ) as unknown as Predicate < R2 > ,
389+ isTupleOf ( predTup , predElse ) as unknown as Predicate <
390+ readonly [ ...ReadonlyTupleOf < T > , ...PredicateType < E > ]
391+ > ,
373392 {
374393 name : {
375394 get : ( ) =>
@@ -449,9 +468,13 @@ export function isUniformTupleOf<T, N extends number>(
449468 n : N ,
450469 pred : Predicate < T > = isAny ,
451470) : Predicate < UniformTupleOf < T , N > > {
452- const predInner = isTupleOf ( Array ( n ) . fill ( pred ) ) ;
453471 return Object . defineProperties (
454- ( x : unknown ) : x is UniformTupleOf < T , N > => predInner ( x ) ,
472+ ( x : unknown ) : x is UniformTupleOf < T , N > => {
473+ if ( ! isArray ( x ) || x . length !== n ) {
474+ return false ;
475+ }
476+ return x . every ( ( v ) => pred ( v ) ) ;
477+ } ,
455478 {
456479 name : {
457480 get : ( ) => `isUniformTupleOf(${ n } , ${ inspect ( pred ) } )` ,
@@ -935,7 +958,9 @@ export function isLiteralOneOf<T extends readonly Primitive[]>(
935958 ) ;
936959}
937960
938- export type OneOf < T > = T extends Predicate < infer U > [ ] ? U : never ;
961+ export type OneOf < T > = T extends readonly [ Predicate < infer U > , ...infer R ]
962+ ? U | OneOf < R >
963+ : never ;
939964
940965/**
941966 * Return a type predicate function that returns `true` if the type of `x` is `OneOf<T>`.
@@ -952,8 +977,25 @@ export type OneOf<T> = T extends Predicate<infer U>[] ? U : never;
952977 * const _: number | string | boolean = a;
953978 * }
954979 * ```
980+ *
981+ * Depending on the version of TypeScript and how values are provided, it may be necessary to add `as const` to the array
982+ * used as `preds`. If a type error occurs, try adding `as const` as follows:
983+ *
984+ * ```ts
985+ * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
986+ *
987+ * const preds = [is.Number, is.String, is.Boolean] as const;
988+ * const isMyType = is.OneOf(preds);
989+ * const a: unknown = 0;
990+ * if (isMyType(a)) {
991+ * // a is narrowed to number | string | boolean
992+ * const _: number | string | boolean = a;
993+ * }
994+ * ```
955995 */
956- export function isOneOf < T extends readonly Predicate < unknown > [ ] > (
996+ export function isOneOf <
997+ T extends readonly [ Predicate < unknown > , ...Predicate < unknown > [ ] ] ,
998+ > (
957999 preds : T ,
9581000) : Predicate < OneOf < T > > {
9591001 return Object . defineProperties (
@@ -986,12 +1028,32 @@ export type AllOf<T> = UnionToIntersection<OneOf<T>>;
9861028 * ]);
9871029 * const a: unknown = { a: 0, b: "a" };
9881030 * if (isMyType(a)) {
989- * // a is narrowed to { a: number; b: string }
990- * const _: { a: number; b: string } = a;
1031+ * // a is narrowed to { a: number } & { b: string }
1032+ * const _: { a: number } & { b: string } = a;
1033+ * }
1034+ * ```
1035+ *
1036+ * Depending on the version of TypeScript and how values are provided, it may be necessary to add `as const` to the array
1037+ * used as `preds`. If a type error occurs, try adding `as const` as follows:
1038+ *
1039+ * ```ts
1040+ * import { is } from "https://deno.land/x/unknownutil@$MODULE_VERSION/mod.ts";
1041+ *
1042+ * const preds = [
1043+ * is.ObjectOf({ a: is.Number }),
1044+ * is.ObjectOf({ b: is.String }),
1045+ * ] as const
1046+ * const isMyType = is.AllOf(preds);
1047+ * const a: unknown = { a: 0, b: "a" };
1048+ * if (isMyType(a)) {
1049+ * // a is narrowed to { a: number } & { b: string }
1050+ * const _: { a: number } & { b: string } = a;
9911051 * }
9921052 * ```
9931053 */
994- export function isAllOf < T extends readonly Predicate < unknown > [ ] > (
1054+ export function isAllOf <
1055+ T extends readonly [ Predicate < unknown > , ...Predicate < unknown > [ ] ] ,
1056+ > (
9951057 preds : T ,
9961058) : Predicate < AllOf < T > > {
9971059 return Object . defineProperties (
0 commit comments