import { Disposable } from "../lifecycle.js"; import { CancellationToken } from "../cancellation.js"; /** * Helper type that represents a function that has an optional {@linkcode CancellationToken} * argument argument at the end of the arguments list. * * @typeparam `TFunction` - Type of the function arguments list of which will be extended * with an optional {@linkcode CancellationToken} argument. */ type TWithOptionalCancellationToken = TFunction extends (...args: infer TArgs) => infer TReturn ? (...args: [ ...TArgs, cancellatioNToken?: CancellationToken ]) => TReturn : never; /** * Decorator that provides a mechanism to cancel previous calls of the decorated method * by providing a `cancellation token` as the last argument of the method, which gets * cancelled immediately on subsequent call of the decorated method. * * Therefore to use this decorator, the two conditions must be met: * * - the decorated method must have an *optional* {@linkcode CancellationToken} argument at * the end of the arguments list * - the object that the decorated method belongs to must implement the {@linkcode Disposable}; * this requirement comes from the internal implementation of the decorator that * creates new resources that need to be eventually disposed by someone * * @typeparam `TObject` - Object type that the decorated method belongs to. * @typeparam `TArgs` - Argument list of the decorated method. * @typeparam `TReturn` - Return value type of the decorated method. * * ### Examples * * ```typescript * // let's say we have a class that implements the `Disposable` interface that we want * // to use the decorator on * class Example extends Disposable { * async doSomethingAsync(arg1: number, arg2: string): Promise { * // do something async.. * await new Promise(resolve => setTimeout(resolve, 1000)); * } * } * ``` * * ```typescript * // to do that we need to add the `CancellationToken` argument to the end of args list * class Example extends Disposable { * @cancelPreviousCalls * async doSomethingAsync(arg1: number, arg2: string, cancellationToken?: CancellationToken): Promise { * console.log(`call with args ${arg1} and ${arg2} initiated`); * * // the decorator will create the cancellation token automatically * assertDefined( * cancellationToken, * `The method must now have the `CancellationToken` passed to it.`, * ); * * cancellationToken.onCancellationRequested(() => { * console.log(`call with args ${arg1} and ${arg2} was cancelled`); * }); * * // do something async.. * await new Promise(resolve => setTimeout(resolve, 1000)); * * // check cancellation token state after the async operations * console.log( * `call with args ${arg1} and ${arg2} completed, canceled?: ${cancellationToken.isCancellationRequested}`, * ); * } * } * * const example = new Example(); * // call the decorate method first time * example.doSomethingAsync(1, 'foo'); * // wait for 500ms which is less than 1000ms of the async operation in the first call * await new Promise(resolve => setTimeout(resolve, 500)); * // calling the decorate method second time cancels the token passed to the first call * example.doSomethingAsync(2, 'bar'); * ``` */ export declare function cancelPreviousCalls(_proto: TObject, methodName: string, descriptor: TypedPropertyDescriptor TReturn>>): TypedPropertyDescriptor<(...args: [ ...TArgs, cancellatioNToken?: CancellationToken | undefined ]) => TReturn>; export {};