Created
February 19, 2024 21:16
-
-
Save SamJakob/1ceb8d43e7a25faa75cb90b8478dfd9b to your computer and use it in GitHub Desktop.
Completer in TypeScript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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