export type AnswerCallback = (result: Result, ...args: Arguments) => Result; export interface IQuestionAsker { ask(result: Result, ...args: Arguments): Result; } export interface IQuestion extends IQuestionAsker { addAnswer(callback: AnswerCallback): void; removeAnswer(callback: AnswerCallback): void; addOneTimeAnswer(callback: AnswerCallback): void; } export class Question implements IQuestion { protected _callbacks: AnswerCallback[] = []; protected _callbacksSet: Set> = new Set(); addAnswer(callback: AnswerCallback) { if (this._callbacksSet.has(callback)) { return; } this._callbacksSet.add(callback); this._callbacks.push(callback); } removeAnswer(callback: AnswerCallback) { if (!this._callbacksSet.has(callback)) { return; } this._callbacksSet.delete(callback); this._callbacks = [...this._callbacksSet]; } addOneTimeAnswer(callback: AnswerCallback) { const onceCallback: AnswerCallback = (...args) => { this.removeAnswer(onceCallback); return callback(...args); }; this.addAnswer(onceCallback); } ask(result: Result, ...args: Arguments): Result { for (const callback of this._callbacks) { result = callback(result, ...args); } return result; } }