Reputation: 1
Let's say I want to create a generic proxy function like this:
type Callback<F extends (...args: any) => any> = F extends (...args: infer P) => infer R
? (
P extends [] ? (onComplete?: (result: R) => void) => void : (parameters: P, onComplete?: (result: R) => void) => void
)
: never;
function createCallback<P extends unknown[], R, F extends (...args: P) => R>(func: F): Callback<F> {
return (parameters?: P | ((result: R) => void), onComplete?: (result: R) => void ): void => {
if (Array.isArray(parameters)) {
R result = func(...parameters);
if (onComplete) {
onComplete(result);
}
} else if (typeof parameters === "function") {
R result = func();
parameters(result);
}
}
}
If the passed function accepts some parameters, then the returned function should have a signature (parameters: [<tuple of function parameters], optional onComplete callback). If the passed function does not accept any parameters, then the returned function should have a signature with a single optional onComplete callback.
Is it possible to do this in TypeScript? The above code won't compile with the error message saying the returned function is not assignable to type Callback.
Upvotes: 0
Views: 523
Reputation: 816
If you're confident that createCallback
does what it's supposed to, it's reasonable to do
return (...) as any as Callback<F>
Alternatively, this makes the compiler happy (playground)
type Callback<F extends (...args: any) => any> = F extends (...args: infer P) => infer R
? (...args: PossibleArguments<P, R>) => void
: never;
type PossibleArguments<P, R, OnComplete = (result: R) => void> =
[] extends P
? ([] | [onComplete: OnComplete])
: ([parameters: P] | [parameters: P, onComplete: OnComplete])
// or
type PossibleArguments<P, R> = [...parameters: [] extends P ? [] : [parameters: P], onComplete?: (result: R) => void]
function createCallback<P extends unknown[], R>(func: (...args: P) => R): Callback<(...args: P) => R> {
return ((...args: PossibleArguments<P, R>): void => {
// ...
})
}
It makes the signature of callbacks ugly, but autocomplete when calling them still works
Upvotes: 1