I have several modules (or bridges) that follow the same format as below:
export interface Bridge {
foo: (a: string, b: boolean, c: string) => number;
bar: (a: number, b: number, c: string, d: string) => string;
x: (a: string) => boolean;
y: () => null;
}
As a result, I need to create a layer than does some if-else processing to import the respective module. However, the functions within these modules will require a fallback mechanism that is made to be generic.
export type BridgeFunctions = keyof Bridge;
/* Called when a particular bridge throws an error */
export async function fallback(fnName: BridgeFunctions, ...args: any[]): Promise<any> {
const fallbackBridge = await import('./fallbackBridge');
const fn = fallbackBridge[fnName];
return fn(...args);
}
However, VSCode returns me this error:
A spread argument must either have a tuple type or be passed to a rest parameter.ts(2556)
Tried using call and apply, which led to this error instead:
The 'this' context of type ... is not assignable to method's 'this' of type '(this: any[]) => Promise<any>'.
Based on my understanding, in vanilla Javascript, passing args straight into fn should work. How do I emulate the same in TypeScript?
EDIT:
The Bridge modules are used as follows:
function getBridge(): Bridge {
if (inIOS()) {
return await import('./ios');
}
// ...
return await import ('./web');
}
export function foo(a: string, b: boolean, c: string): number {
try {
const bridge = await getBridge();
return bridge.foo(a, b, c);
} catch (error: any) {
// ...
if (error.bridge.failed) {
return await fallback('foo', a, b, c);
}
}
}
The problem here is that your fallbackBridge functions require a certain number of parameters but you give them the type " any[] " that could have any length.
You could bypass this error with return fn(...(args as Parameters<typeof fn>));
This is how I would do it.
Basically, you want to make sure the user passes valid arguments to your function. To do this, you set the args to be the parameters of the passed in function.
export async function fallback<FN extends keyof Bridge>(fnName: FN, args: Parameters<Bridge[FN]>){
Then, to bypass the error, just type fn to any:
const fn = fallbackBridge[fnName] as any;
return fn(...args);
Using any here is fine since you already know the types are compatible.