Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: enhance typeguard function type #211

Merged
merged 2 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/isArray.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Returns true if `a` is an Array.
*
Expand All @@ -7,8 +9,7 @@
* isArray(2); // false
* ```
*/
function isArray(a: any): a is any[] {
return Array.isArray(a);
}
const isArray = <T>(a: T): a is Include<T, unknown[] | Readonly<unknown[]>> =>
Array.isArray(a);

export default isArray;
6 changes: 3 additions & 3 deletions src/isBoolean.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Returns true if `n` is a Boolean.
*
Expand All @@ -8,8 +10,6 @@
* isBoolean("FxTS"); // false
* ```
*/
function isBoolean(n: unknown): n is boolean {
return typeof n === "boolean";
}
const isBoolean = <T>(n: T): n is Include<T, boolean> => typeof n === "boolean";

export default isBoolean;
2 changes: 1 addition & 1 deletion src/isEmpty.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import isNil from "./isNil";
* isEmpty(new Date()) // false
* ```
*/
export const isEmpty = (value: unknown): boolean => {
const isEmpty = <T>(value: T): boolean => {
if (isNil(value)) return true; // if value is null or undefined.

if (
Expand Down
6 changes: 3 additions & 3 deletions src/isNil.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import isNull from "./isNull";
import isUndefined from "./isUndefined";

type Nullable<T> = T extends null | undefined ? T : never;
import type Include from "./types/Include";

/**
* Checks if the given value is `null` or `undefined`.
Expand All @@ -14,6 +13,7 @@ type Nullable<T> = T extends null | undefined ? T : never;
* isNil(null); // true
* ```
*/
const isNil = <T>(a: T): a is Nullable<T> => isUndefined(a) || isNull(a);
const isNil = <T>(a: T): a is Include<T, null | undefined> =>
isUndefined(a) || isNull(a);

export default isNil;
4 changes: 3 additions & 1 deletion src/isNull.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Checks if the given value is `null`.
*
Expand All @@ -9,6 +11,6 @@
* isNull(null); // true
* ```
*/
const isNull = <T>(input: T | null): input is null => input === null;
const isNull = <T>(input: T): input is Include<T, null> => input === null;

export default isNull;
6 changes: 3 additions & 3 deletions src/isNumber.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Returns true if `n` is a Number.
*
Expand All @@ -7,8 +9,6 @@
* isNumber("a"); // false
* ```
*/
function isNumber(n: unknown): n is number {
return typeof n === "number";
}
const isNumber = <T>(n: T): n is Include<T, number> => typeof n === "number";

export default isNumber;
6 changes: 3 additions & 3 deletions src/isObject.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
type IdentityObject<T> = T extends object ? T : never;
import type Include from "./types/Include";

/**
* Checks if value is the type of object.
Expand All @@ -12,9 +12,9 @@ type IdentityObject<T> = T extends object ? T : never;
* isObject(123); // false
* ```
*/
function isObject<T = unknown>(a: T): a is IdentityObject<T> {
const isObject = <T>(a: T): a is Include<T, object> => {
const type = typeof a;
return a != null && (type === "object" || type === "function");
}
};

export default isObject;
6 changes: 3 additions & 3 deletions src/isString.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Returns true if `s` is a String.
*
Expand All @@ -7,8 +9,6 @@
* isString(2); // false
* ```
*/
function isString(s: unknown): s is string {
return typeof s === "string";
}
const isString = <T>(s: T): s is Include<T, string> => typeof s === "string";

export default isString;
4 changes: 3 additions & 1 deletion src/isUndefined.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import type Include from "./types/Include";

/**
* Checks if the given value is `undefined`.
*
Expand All @@ -7,6 +9,6 @@
* isUndefined(2); // false
* ```
*/
const isUndefined = <T>(a: T | undefined): a is undefined => a === undefined;
const isUndefined = <T>(a: T): a is Include<T, undefined> => a === undefined;

export default isUndefined;
2 changes: 1 addition & 1 deletion src/last.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ function last<T extends Iterable<unknown> | AsyncIterable<unknown>>(
iterable: T,
): LastReturnType<T>;

function last<A>(iterable: Iterable<A> | AsyncIterable<A>) {
function last<A>(iterable: Iterable<A> | AsyncIterable<A> | A[]) {
if (isArray(iterable) || isString(iterable)) {
return iterable[iterable.length - 1];
}
Expand Down
2 changes: 1 addition & 1 deletion src/sort.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function sort<T extends Iterable<unknown> | AsyncIterable<unknown>>(
}

if (isArray(iterable)) {
return iterable.sort(f as any);
return (iterable as any[]).sort(f as any);
}

if (isIterable(iterable)) {
Expand Down
2 changes: 1 addition & 1 deletion src/sortBy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ function sortBy<T extends Iterable<unknown> | AsyncIterable<unknown>>(
};

if (isArray(iterable)) {
return iterable.sort(_sortBy);
return (iterable as any).sort(_sortBy);
}

if (isIterable(iterable)) {
Expand Down
16 changes: 15 additions & 1 deletion type-check/isArray.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
import { isArray } from "../src";
import { isArray, negate, pipe, throwIf } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;

const res1 = isArray([1, 2, 3]);
const res2 = isArray("a");

const res3 = pipe(
[1, 2, 3] as const,

throwIf(negate(isArray)),
);

const res4 = pipe(
[1, 2, 3],

throwIf(negate(isArray)),
);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, readonly [1, 2, 3], Test.Pass>(),
check<typeof res4, number[], Test.Pass>(),
]);
7 changes: 6 additions & 1 deletion type-check/isBoolean.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isBoolean, pipe } from "../src";
import { filter, isBoolean, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;
Expand All @@ -7,8 +7,13 @@ const res1 = isBoolean(true);
const res2 = isBoolean("a");
const res3 = pipe(true, isBoolean);

const res4 = pipe([true, 1, true, 2] as const, filter(isBoolean), toArray);
const res5 = pipe([1, 2] as const, filter(isBoolean), toArray);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, boolean, Test.Pass>(),
check<typeof res4, true[], Test.Pass>(),
check<typeof res5, never[], Test.Pass>(),
]);
22 changes: 21 additions & 1 deletion type-check/isNil.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNil, map, pipe, toArray } from "../src";
import { filter, isNil, map, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;
Expand All @@ -23,7 +23,27 @@ function getUserName(user: User) {
const res1 = getUserName(user);
const res2 = pipe([user, user, user], map(getUserName), toArray);

const res3 = pipe(
[null, undefined, 2, 3, true, "", null],
filter(isNil),
toArray,
);

const res4 = pipe([null, 2, 3, true, "", null], filter(isNil), toArray);

const res5 = pipe(
[undefined, 2, 3, true, "", undefined],
filter(isNil),
toArray,
);

const res6 = pipe([2, 3, true, ""], filter(isNil), toArray);

checks([
check<typeof res1, string, Test.Pass>(),
check<typeof res2, string[], Test.Pass>(),
check<typeof res3, (null | undefined)[], Test.Pass>(),
check<typeof res4, null[], Test.Pass>(),
check<typeof res5, undefined[], Test.Pass>(),
check<typeof res6, never[], Test.Pass>(),
]);
8 changes: 5 additions & 3 deletions type-check/isNull.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
import { filter, isNull, pipe } from "../src";
import { filter, isNull, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;

const res1 = isNull(undefined);
const res2 = isNull(null);
const res3 = isNull(3);
const res4 = pipe([1, null, 2], filter(isNull));
const res4 = pipe([1, null, 2], filter(isNull), toArray);
const res5 = pipe([1, 2, 3], filter(isNull), toArray);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, boolean, Test.Pass>(),
check<typeof res4, IterableIterator<null>, Test.Pass>(),
check<typeof res4, null[], Test.Pass>(),
check<typeof res5, never[], Test.Pass>(),
]);
20 changes: 19 additions & 1 deletion type-check/isNumber.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNumber, pipe } from "../src";
import { filter, isNumber, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;
Expand All @@ -7,8 +7,26 @@ const res1 = isNumber(1);
const res2 = isNumber("a");
const res3 = pipe(1, isNumber);

const res4 = pipe(
[1, 2, "", null, 3] as const,

filter(isNumber),

toArray,
);

const res5 = pipe(
[null, undefined],

filter(isNumber),

toArray,
);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, boolean, Test.Pass>(),
check<typeof res4, (1 | 2 | 3)[], Test.Pass>(),
check<typeof res5, never[], Test.Pass>(),
]);
20 changes: 19 additions & 1 deletion type-check/isObject.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isObject } from "../src";
import { filter, isObject, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;
Expand All @@ -8,6 +8,22 @@ const res2 = isObject("a");
const res3 = isObject(() => "");
const res4 = isObject(Math.random() > 0.5 ? {} : null);

const res5 = pipe(
[{}, { a: 1 }],

filter(isObject),

toArray,
);

const res6 = pipe(
[1, 2, null],

filter(isObject),

toArray,
);

type Node = {
id: number;
name: string;
Expand All @@ -28,4 +44,6 @@ checks([
check<typeof res3, boolean, Test.Pass>(),
check<typeof res4, boolean, Test.Pass>(),
check<ReturnType<typeof getChildNodeId>, number, Test.Pass>(),
check<typeof res5, { a?: number }[], Test.Pass>(),
check<typeof res6, never[], Test.Pass>(),
]);
20 changes: 19 additions & 1 deletion type-check/isString.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
import { isString } from "../src";
import { filter, isString, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;

const res1 = isString(1);
const res2 = isString("a");

const res3 = pipe(
["1", "2", "3", 4, 5, null] as const,

filter(isString),

toArray,
);

const res4 = pipe(
[4, 5, null] as const,

filter(isString),

toArray,
);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, ("1" | "2" | "3")[], Test.Pass>(),
check<typeof res4, never[], Test.Pass>(),
]);
8 changes: 5 additions & 3 deletions type-check/isUndefined.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { filter, isUndefined, pipe } from "../src";
import { filter, isUndefined, pipe, toArray } from "../src";
import * as Test from "../src/types/Test";

const { checks, check } = Test;

const res1 = isUndefined(undefined);
const res2 = isUndefined(3);
const res3 = pipe([1, undefined, 2], filter(isUndefined));
const res3 = pipe([1, undefined, 2], filter(isUndefined), toArray);
const res4 = pipe([1, 2, 3], filter(isUndefined), toArray);

checks([
check<typeof res1, boolean, Test.Pass>(),
check<typeof res2, boolean, Test.Pass>(),
check<typeof res3, IterableIterator<undefined>, Test.Pass>(),
check<typeof res3, undefined[], Test.Pass>(),
check<typeof res4, never[], Test.Pass>(),
]);