'How to have functions pass arguments with the same overloads?
I am trying to create a function passes its arguments to another function. Both of these functions need to have the same overloads.
function original (a: number): boolean;
function original (a: string, b: string): boolean;
function original (a: number | string, b?: string): boolean {
return true;
}
function pass (a: number): boolean;
function pass (a: string, b: string): boolean;
function pass (a: number | string, b?: string): boolean {
return original(a, b);
}
This does not work.
Argument of type 'string | number' is not assignable to parameter of type 'string'.
Type 'number' is not assignable to type 'string'.(2345) input.tsx(4, 10): The call would have succeeded against this implementation, but implementation signatures of overloads are not externally visible.
Solution 1:[1]
You can just declare your pass function as being of the type of the original function using the typeof operator, e.g.
function original (a: number): boolean;
function original (a: string, b: string): boolean;
function original (): boolean {
return true;
}
let pass: typeof original = () => {
return true;
};
pass(5); // all good
pass('a', 'b'); // all godd
pass(45, 'b'); // error here
Solution 2:[2]
Add extra overload:
function original<
A extends number | string,
B extends A extends string ? string : undefined
>(a: A, b: B): boolean;
Now it looks like:
function original(a: number): boolean;
function original(a: string, b: string): boolean;
function original<
A extends number | string,
B extends A extends string ? string : undefined
>(a: A, b: B): boolean;
function original(a: number | string, b?: string): boolean {
return true;
}
function pass(a: number): boolean;
function pass(a: string, b: string): boolean;
function pass(a: number | string, b?: string): boolean {
return original(a, b); // Works
}
const t1 = original(1); // Works
const t2 = original("foo", "foo"); // Works
const t3 = original(1, "foo"); // Works: gives an error as expected
const t4 = original("foo"); // Works: gives an error as expected
You no more need the second overload function original(a: string, b: string): boolean but you may still leave it for better readability of the code.
Solution 3:[3]
Here's a solution which doesn't use type assertions and doesn't change or add any overload signatures to either function: use an IIFE to create both functions, where the functions have the weaker signature inside the IIFE's "private" scope, but the stronger signature outside.
interface OriginalSignature {
(a: number): boolean;
(a: string, b: string): boolean;
}
const [original, pass] = (function(): [OriginalSignature, OriginalSignature] {
function original(a: number | string, b?: string): boolean {
return true;
}
function pass(a: number | string, b?: string): boolean {
return original(a, b);
}
return [original, pass];
})();
Tests:
// OK
original(1);
original('a', 'b');
pass(1);
pass('a', 'b');
// errors
original('a');
original(1, 'b');
pass('a');
pass(1, 'b');
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | dezfowler |
| Solution 2 | Andrei Kovalev |
| Solution 3 | kaya3 |
