Skip to content

Instantly share code, notes, and snippets.

@SamJakob
Created February 19, 2024 21:16
Show Gist options
  • Save SamJakob/1ceb8d43e7a25faa75cb90b8478dfd9b to your computer and use it in GitHub Desktop.
Save SamJakob/1ceb8d43e7a25faa75cb90b8478dfd9b to your computer and use it in GitHub Desktop.
Completer in TypeScript
/**
* This is a TypeScript version of the `Completer` class from Dart.
*
* A `Completer` provides a future that can be imperatively concluded (once and
* only once) with either `#complete` or `#completeError`.
* Once the completer has completed (or errored), the future will be resolved
* with the specified value.
*
* This is trivially implemented by instantiating a Promise and capturing the
* resolve and reject functions.
*/
export class Completer<T> {
readonly #promise: Promise<T>;
#resolve: (value: (T | PromiseLike<T>)) => void;
#reject: (reason?: any) => void;
#completed = false;
/**
* Initialize a {@link Completer}.
*
* A Completer provides a future that can be imperatively concluded (once)
* with either {@link #complete} or {@link #completeError}. Once the
* completer has completed (or errored), the future will be resolved with
* the specified value. It will then not be possible to complete the
* completer again (as it will throw an error if an attempt is made to do
* so).
*/
public constructor() {
// Initialize #resolve and #reject with a function that throws an error
// so errors are not silently swallowed if the completer is not
// initialized properly.
const failedInitialize = () => {
throw new Error("Completer failed to initialize");
};
this.#resolve = failedInitialize;
this.#reject = failedInitialize;
// Initialize the #promise property with a new promise and define the
// #resolve and #reject functions to be the resolve and reject functions
// of the promise.
this.#promise = new Promise((resolve, reject) => {
this.#resolve = resolve;
this.#reject = reject;
});
}
/**
* Returns the promise that can be used to observe the completion of the
* completer.
*/
public get promise(): Promise<T> { return this.#promise; }
/**
* Returns true if either {@link #complete} or {@link #completeError} has
* been called on the completer.
*/
public get completed(): boolean { return this.#completed; }
/**
* Complete the completer with the specified value.
* @param value The value to complete the completer with.
*/
public complete(value: T) {
if (this.#completed) {
throw new Error("Completer has already completed");
}
this.#completed = true;
this.#resolve(value);
}
/**
* Complete the completer with the specified error.
* @param error The error to complete the completer with.
*/
public completeError(error: any) {
if (this.#completed) {
throw new Error("Completer has already completed");
}
this.#completed = true;
this.#reject(error);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment