Consider a TypeScript function that takes either a string
or a Promise<string>
as input and returns an answer of the same type. Here's an example:
function trim(textOrPromise) {
if (textOrPromise.then) {
return textOrPromise.then(value => result.trim());
}
return textOrPromise.trim();
}
I want to use generics in defining the function signature to ensure that passing a Promise
always results in a Promise
, while passing a string
gives back a string
To achieve this, I create the following overloads:
function trim(text: Promise<string>): Promise<string>
function trim(text: string): string
function trim(text: any): any {
if (text.then) {
return text.then(result => result.trim()); // returns Promise<string>
}
return text.trim(); // returns string
}
This transpiles correctly when the parameter is explicitly defined as string
or Promise<string>
:
let value: string
trim(value) // works fine
let value: Promise<string>
trim(value) // works fine
But, when using a union type (Promise<string> | string
) for the parameter:
let value: Promise<string> | string
trim(value) // error: TS2769
The transpilation error received is:
TS2769: No overload matches this call.
Overload 1 of 2, '(text: Promise<string>): Promise<string>', gave the following error.
Argument of type 'string | Promise<string>' is not assignable to parameter of type 'Promise<string>'.
Type 'string' is not assignable to type 'Promise<string>'.
Overload 2 of 2, '(text: string): string', gave the following error.
Argument of type 'string | Promise<string>' is not assignable to parameter of type 'string'.
Type 'Promise<string>' is not assignable to type 'string'.
Interestingly, adding the union type to the function signature resolves the issue:
function trim(text: Promise<string>): Promise<string>
function trim(text: string): string
function trim(text: Promise<string> | string): Promise<string> | string
function trim(text: any): any {
if (text.then) {
return text.then(result => result.trim());
}
return text.trim();
}
let value: Promise<string> | string
trim(value) // works fine
With this implementation, TypeScript correctly infers that the function returns a Promise
or a string
based on the input it receives. This contrasts with the behavior suggested by a union of Promise<string> | string
in the third overload.
If anyone can explain why this happens and the necessity of overloads for union types, I would greatly appreciate it.