Skip to content

Commit

Permalink
feat: add isDisposable
Browse files Browse the repository at this point in the history
  • Loading branch information
crimx committed Jan 23, 2025
1 parent 5e251b4 commit 18536b6
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 9 deletions.
5 changes: 2 additions & 3 deletions src/abortable.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- used in type doc
type Disposer,
} from "./interface";
import { dispose, isFn } from "./utils";
import { dispose, isDisposable, isFn } from "./utils";

/**
* A {@link DisposableDisposer} that can be safely self-disposed.
Expand Down Expand Up @@ -69,6 +69,5 @@ function abortable$abortable(
export const isAbortable = (
disposable: any
): disposable is AbortableDisposable =>
isFn(disposable) &&
isFn((disposable as AbortableDisposable).dispose) &&
isDisposable(disposable) &&
isFn((disposable as AbortableDisposable).abortable);
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export type {
IDisposable,
} from "./interface";
export { join } from "./join";
export { dispose } from "./utils";
export { dispose, isDisposable } from "./utils";
6 changes: 2 additions & 4 deletions src/join.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { type DisposableType, type Disposer } from "./interface";
import { dispose } from "./utils";

export const join =
(...disposers: DisposableType[]): Disposer =>
() =>
disposers.forEach(dispose);
export const join = (...disposers: DisposableType[]): Disposer =>
disposers.forEach.bind(disposers, dispose);
9 changes: 8 additions & 1 deletion src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import { type Disposer, type IDisposable } from "./interface";
import {
type DisposableType,
type Disposer,
type IDisposable,
} from "./interface";

export const isFn = (value: any): value is (...args: any[]) => any =>
!!(value && value.constructor && value.call && value.apply);

export const isDisposable = (value: any): value is DisposableType =>
isFn(value as Disposer) || isFn((value as IDisposable)?.dispose);

/**
* Dispose a disposable object or a disposer function. Log the error if any.
* @param disposable A disposable object or a disposer function. Do nothing otherwise.
Expand Down
26 changes: 26 additions & 0 deletions test/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { describe, expect, it } from "vitest";

import { type Disposer, type IDisposable, isDisposable } from "../src";

describe("isDisposable", () => {
it("should returns true for Disposer", () => {
const a = () => void 0;
const b: Disposer = () => void 0;
expect(isDisposable(a)).toBe(true);
expect(isDisposable(b)).toBe(true);
});

it("should returns true for IDisposable", () => {
const a = { dispose() {} };
const b: IDisposable = { dispose: () => {} };
expect(isDisposable(a)).toBe(true);
expect(isDisposable(b)).toBe(true);
});

it("should returns false for other types", () => {
const a = {};
const b = () => {};
expect(isDisposable(a)).toBe(false);
expect(isDisposable(b)).toBe(false);
});
});

0 comments on commit 18536b6

Please sign in to comment.