1.3.2 • Published 4 months ago

@tioniq/disposiq v1.3.2

Weekly downloads
-
License
MIT
Repository
github
Last release
4 months ago

Disposiq

Coverage npm version JSR npm bundle size tree-shakeable types downloads license

Disposiq is a utility collection of Dispose pattern.

This library is compatible with upcoming Explicit Resource Management API which is already implemented in Typescript 5.2

Are you lazy about cleaning up resources? Does your code look messy, and do you want to make it cleaner and easier to read? Are you tired of writing the same code for cleaning up resources over and over again? Have you wanted to use the Dispose pattern in your project, but you don't know how to start? Then this library is for you!

Stop talking, show me the code!

Installation

You can install the library using npm:

npm install @tioniq/disposiq

Function as a disposable

import { DisposableAction } from '@tioniq/disposiq'

// The action will be executed only once when the disposable is disposed
const disposable = new DisposableAction(() => {
  console.log('Resource cleaned up')
})
disposable.dispose() // Output: Resource cleaned up
disposable.dispose() // No output

Store-based disposable

import { DisposableStore, DisposableAction } from '@tioniq/disposiq'

const store = new DisposableStore()
const disposable1 = new DisposableAction(() => {
  console.log('Resource cleaned up 1')
})
// DisposableStore accepts functions as disposables
const disposable2 = () => {
  console.log('Resource cleaned up 2')
}
store.add(disposable1)
store.add(disposable2)
store.dispose() // Output: Resource cleaned up 1, Resource cleaned up 2

const disposable3 = () => {
  console.log('Resource cleaned up 3')
}

// After disposing of the store, all disposables added to the store will be disposed of immediately
store.add(disposable3) // Output: Resource cleaned up 3

Store-based disposable to dispose temporary resources

import { DisposableStore, DisposableAction } from '@tioniq/disposiq'

const store = new DisposableStore()
const disposable1 = new DisposableAction(() => {
  console.log('Resource cleaned up 1')
})
const disposable2 = new DisposableAction(() => {
  console.log('Resource cleaned up 2')
})
// You can add multiple disposables at once
store.add(disposable1, disposable2)

// Dispose of the current disposables in the store without disposing of the store itself
store.disposeCurrent() // Output: Resource cleaned up 1, Resource cleaned up 2

// The store is still active, but all contained disposables are disposed of and removed from the store
// You can now add new disposables to the store
store.add(() => {
  console.log('Resource cleaned up 3')
}) // No output

// Dispose the store completely
store.dispose() // Output: Resource cleaned up 3

Explicit Resource Management API support (aka 'using' keyword)

import { DisposableStore, DisposableAction } from '@tioniq/disposiq'

// When using the new 'using' keyword, the disposable will be disposed of automatically when it goes out of scope
{
  using disposable = new DisposableAction(() => {
    console.log('Resource cleaned up')
  })
}
// Output: Resource cleaned up

// It also works with other disposable objects from the library. For example, DisposableStore:
{
  using store = new DisposableStore()
  store.add(new DisposableAction(() => {
    console.log('Resource cleaned up')
  }))
} // Output: Resource cleaned up

If you cannot use 'using' keyword

There is a way to achieve the same result without use of the 'using' keyword. You can use the 'using' function instead.

import { Disposable, using } from '@tioniq/disposiq'

using(new Client(), async (client) => {
  await client.makeRequest() // Output: Request made
}) // Output: Resource cleaned up

class Client extends Disposable {
  constructor() {
    super()
    this.addDisposable(() => {
      console.log('Resource cleaned up')
    })
  }

  async makeRequest() {
    console.log('Request made')
  }
}

You can find a simple example here. Also, check out another project built with Disposiq: Eventiq. It's an implementation of the Observer pattern using Disposiq. It's an interesting project worth exploring!

Extensions

The library is flexible and can be extended to custom functionality. All classes in the library extend the Disposiq class, so you can add custom methods to the class. For example, you can add a custom method to the Disposiq class:

import { Disposiq, DisposableAction, IDisposable } from '@tioniq/disposiq'

declare module '@tioniq/disposiq' {
  interface Disposiq {
    togetherWith(other: IDisposable): Disposiq
  }
}

Disposiq.prototype.togetherWith = function (this: Disposiq, other: IDisposable): Disposiq {
  return new DisposableAction(() => {
    this.dispose()
    other.dispose()
  })
}

Inspiration

This library is inspired by the

  • Dispose pattern and its principles
  • The usage of disposables in Monaco Editor and VSCode
  • The usage of disposables in RxJava and ReactiveX
  • The C# IDisposable interface
  • The core concept used by major projects like Angular, React, Vue, etc., which utilize a return function or component method to clean up resources

Documentation

Interfaces & Types

InterfaceShort Description
IDisposableBase interface for disposables
IAsyncDisposableBase interface for asynchronous disposables
DisposeFuncA function with no parameters
DisposableLikeA function or disposable object
AsyncDisposableLikeA function that returns a Promise or an async disposable object
AsyncDisposeFuncAn asynchronous function with no parameters
IDisposablesContainerA container for a collection of disposables
DisposableAwareRepresents a disposable that is aware of its state
DisposableCompatRepresents a disposable compatible with the 'using' keyword
DisposableAwareCompatCombines DisposableAware and DisposableCompat
AsyncDisposableAwareAn asynchronous disposable that is aware of its state
AsyncDisposableCompatAn asynchronous disposable compatible with the 'using' keyword
AsyncDisposableAwareCompatCombines AsyncDisposableAware and AsyncDisposableCompat

Classes

ClassShort DescriptionAliases
DisposiqBase class for all library disposables- BaseDisposable
AsyncDisposiqBase class for all library asynchronous disposables- BaseAsyncDisposable
DisposableActionA container for a function to be called on dispose-
AsyncDisposableActionA container for an asynchronous function to be called on dispose-
DisposableStoreA container for disposablesCompositeDisposable
AsyncDisposableStoreA container for async disposablesCompositeAsyncDisposable
DisposableMapStoreA container for disposables stored by a keyDisposableDictionary
DisposableContainerA container for a disposable objectSerialDisposable
BoolDisposableA object that aware of its disposed stateBooleanDisposable
SafeActionDisposableA container for a function that is safely called on dispose-
SafeAsyncActionDisposableA container for an asynchronous function that is safely called on dispose-
AbortDisposableA wrapper for AbortController to make it disposable-
ObjectDisposedExceptionAn exception thrown when an object is already disposed-

Functions

ClassShort DescriptionAliases
disposeAllDispose of all disposables in the array safely, allowing array modification during disposaldisposeAllSafe
disposeAllUnsafeDispose of all disposables in the array unsafely, array modification during disposal is dangerous-
disposeAllSafelyDispose of all disposables in the array safely, with error callback, array modification during disposal is dangerous-
createDisposableCreate a disposable object from a given parametertoDisposable
createDisposableCompatCreate a disposable object from a given parameter compatible with the 'using' keywordtoDisposableCompat
disposableFromEventCreate a disposable object from an event listeneron
disposableFromEventOnceCreate a disposable object from an event listener that disposes after the first callonce
isDisposableCheck if the object is a disposable object-
isDisposableLikeCheck if the object is a disposable-like-
isDisposableCompatCheck if the object is a disposable object that is compatible with the 'using' keyword-
isAsyncDisposableCompatCheck if the object is an asynchronous disposable object that is compatible with the 'using' keyword-
isSystemDisposableCheck if the object is compatible with the system 'using' keyword-
isSystemAsyncDisposableCheck if the object is compatible with the system 'await using' keyword-
addEventListenerAdd an event listener to the target object and return a disposable object. Useful for DOM events-

For more information, please check the type definitions file.

Contributing

Contributions are welcome! Please open an issue or submit a pull request on GitHub. Remember to write tests for your changes.

License

This project is licensed under the MIT License.

1.3.2

4 months ago

1.3.1

4 months ago

1.3.0

5 months ago

1.2.5

5 months ago

1.2.4

5 months ago

1.2.3

5 months ago

1.2.2

6 months ago

1.2.1

6 months ago

1.2.0

6 months ago

1.1.4

6 months ago

1.1.3

7 months ago

1.1.2

7 months ago

1.1.1

7 months ago

1.1.0

7 months ago

1.0.20

7 months ago

1.0.19

8 months ago

1.0.18

8 months ago

1.0.17

8 months ago

1.0.16

8 months ago

1.0.15

8 months ago

1.0.14

9 months ago

1.0.13

9 months ago

1.0.12

9 months ago

1.0.11

9 months ago

1.0.9

10 months ago

1.0.10

9 months ago

1.0.8

10 months ago

1.0.7

10 months ago

1.0.6

10 months ago

1.0.5

10 months ago

1.0.4

10 months ago

1.0.3

10 months ago

1.0.2

10 months ago

1.0.1

10 months ago

1.0.0

10 months ago