Skip to content

Commit 1c0e7a8

Browse files
authored
Merge pull request #24 from lambdalisue/add-is-instanceof
👍 Add `isInstanceOf<T>`, `isBigInt`, and `isSymbol` functions
2 parents 4750817 + 256a509 commit 1c0e7a8

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

is.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,13 @@ export function isNumber(x: unknown): x is number {
1717
return typeof x === "number";
1818
}
1919

20+
/**
21+
* Return `true` if the type of `x` is `bigint`.
22+
*/
23+
export function isBigInt(x: unknown): x is bigint {
24+
return typeof x === "bigint";
25+
}
26+
2027
/**
2128
* Return `true` if the type of `x` is `boolean`.
2229
*/
@@ -161,6 +168,26 @@ export function isFunction(x: unknown): x is (...args: unknown[]) => unknown {
161168
return Object.prototype.toString.call(x) === "[object Function]";
162169
}
163170

171+
/**
172+
* Return `true` if the type of `x` is instance of `ctor`.
173+
*
174+
* ```ts
175+
* import is from "./is.ts";
176+
*
177+
* const a: unknown = new Date();
178+
* if (is.InstanceOf(Date)(a)) {
179+
* // a is narrowed to Date
180+
* const _: Date = a;
181+
* }
182+
* ```
183+
*/
184+
// deno-lint-ignore no-explicit-any
185+
export function isInstanceOf<T extends new (...args: any) => unknown>(
186+
ctor: T,
187+
): Predicate<InstanceType<T>> {
188+
return (x: unknown): x is InstanceType<T> => x instanceof ctor;
189+
}
190+
164191
/**
165192
* Return `true` if the type of `x` is `null`.
166193
*/
@@ -182,6 +209,13 @@ export function isNullish(x: unknown): x is null | undefined {
182209
return x == null;
183210
}
184211

212+
/**
213+
* Return `true` if the type of `x` is `symbol`.
214+
*/
215+
export function isSymbol(x: unknown): x is symbol {
216+
return typeof x === "symbol";
217+
}
218+
185219
export type OneOf<T> = T extends (infer U)[]
186220
? T extends Predicate<infer U>[] ? U : T
187221
: T;
@@ -209,6 +243,7 @@ export function isOneOf<T extends readonly Predicate<unknown>[]>(
209243
export default {
210244
String: isString,
211245
Number: isNumber,
246+
BigInt: isBigInt,
212247
Boolean: isBoolean,
213248
Array: isArray,
214249
ArrayOf: isArrayOf,
@@ -217,8 +252,10 @@ export default {
217252
RecordOf: isRecordOf,
218253
ObjectOf: isObjectOf,
219254
Function: isFunction,
255+
InstanceOf: isInstanceOf,
220256
Null: isNull,
221257
Undefined: isUndefined,
222258
Nullish: isNullish,
259+
Symbol: isSymbol,
223260
OneOf: isOneOf,
224261
};

is_test.ts

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import {
55
import is, {
66
isArray,
77
isArrayOf,
8+
isBigInt,
89
isBoolean,
910
isFunction,
11+
isInstanceOf,
1012
isNull,
1113
isNullish,
1214
isNumber,
@@ -15,6 +17,7 @@ import is, {
1517
isRecord,
1618
isRecordOf,
1719
isString,
20+
isSymbol,
1821
isTupleOf,
1922
isUndefined,
2023
Predicate,
@@ -23,16 +26,19 @@ import is, {
2326
const examples = {
2427
string: ["", "Hello world"],
2528
number: [0, 1234567890],
29+
bigint: [0n, 1234567890n],
2630
boolean: [true, false],
2731
array: [[], [0, 1, 2], ["a", "b", "c"], [0, "a", true]],
2832
record: [{}, { a: 0, b: 1, c: 2 }, { a: "a", b: "b", c: "c" }],
2933
function: [function () {}],
3034
null: [null],
3135
undefined: [undefined],
36+
symbol: [Symbol("a"), Symbol("b"), Symbol("c")],
3237
};
3338

3439
function stringify(x: unknown): string {
3540
if (typeof x === "function") return x.toString();
41+
if (typeof x === "bigint") return `${x}n`;
3642
return JSON.stringify(x);
3743
}
3844

@@ -62,6 +68,10 @@ Deno.test("isNumber", async (t) => {
6268
await testWithExamples(t, isNumber, ["number"]);
6369
});
6470

71+
Deno.test("isBigInt", async (t) => {
72+
await testWithExamples(t, isBigInt, ["bigint"]);
73+
});
74+
6575
Deno.test("isBoolean", async (t) => {
6676
await testWithExamples(t, isBoolean, ["boolean"]);
6777
});
@@ -180,6 +190,46 @@ Deno.test("isFunction", async (t) => {
180190
await testWithExamples(t, isFunction, ["function"]);
181191
});
182192

193+
Deno.test("isInstanceOf<T>", async (t) => {
194+
await t.step("returns true on T instance", () => {
195+
class Cls {}
196+
assertEquals(isInstanceOf(Cls)(new Cls()), true);
197+
assertEquals(isInstanceOf(Date)(new Date()), true);
198+
assertEquals(isInstanceOf(Promise<string>)(new Promise(() => {})), true);
199+
});
200+
await t.step("returns false on non function", () => {
201+
class Cls {}
202+
assertEquals(isInstanceOf(Cls)(new Date()), false);
203+
assertEquals(isInstanceOf(Cls)(new Promise(() => {})), false);
204+
assertEquals(isInstanceOf(Cls)(""), false);
205+
assertEquals(isInstanceOf(Cls)(0), false);
206+
assertEquals(isInstanceOf(Cls)(true), false);
207+
assertEquals(isInstanceOf(Cls)(false), false);
208+
assertEquals(isInstanceOf(Cls)([]), false);
209+
assertEquals(isInstanceOf(Cls)({}), false);
210+
assertEquals(isInstanceOf(Cls)(function () {}), false);
211+
assertEquals(isInstanceOf(Cls)(null), false);
212+
assertEquals(isInstanceOf(Cls)(undefined), false);
213+
});
214+
await t.step("returns proper type predicate", () => {
215+
class Cls {}
216+
const a: unknown = new Cls();
217+
if (isInstanceOf(Cls)(a)) {
218+
const _: Cls = a;
219+
}
220+
221+
const b: unknown = new Date();
222+
if (isInstanceOf(Date)(b)) {
223+
const _: Date = b;
224+
}
225+
226+
const c: unknown = new Promise(() => {});
227+
if (isInstanceOf(Promise)(c)) {
228+
const _: Promise<unknown> = c;
229+
}
230+
});
231+
});
232+
183233
Deno.test("isNull", async (t) => {
184234
await testWithExamples(t, isNull, ["null"]);
185235
});
@@ -192,6 +242,10 @@ Deno.test("isNullish", async (t) => {
192242
await testWithExamples(t, isNullish, ["null", "undefined"]);
193243
});
194244

245+
Deno.test("isSymbol", async (t) => {
246+
await testWithExamples(t, isSymbol, ["symbol"]);
247+
});
248+
195249
Deno.test("isOneOf<T>", async (t) => {
196250
await t.step("returns proper type predicate", () => {
197251
const preds = [isNumber, isString, isBoolean];

0 commit comments

Comments
 (0)