I'm currently working on a TypeScript function that can handle either an A
type or a Promise<A>
. In this case, A
represents a specific concrete type, and the function should return the same type. If it receives a Promise<A>
, then the return type will also be Promise<A>
, and vice versa.
I tried creating a conditional return type based on the input type like this:
func<T = A | Promise<A>, R = T extends A ? A : Promise<A>>(arg: T): R
. However, when I use a type guard to assert that arg is Promise<A>
, the type becomes T & Promise<A>
in one branch and remains as T
in the other. I expected it to become A
and Promise<A>
.
On the other hand, if I create a function like
func(arg: A | Promise<A>): void
, the type guard works correctly. It identifies the actual types as A
in one branch and Promise<A>
in the other. However, I'm struggling to apply this typing to the return value.
interface A {
x(): void;
}
interface Promise<T> {
}
function isPromise<T>(obj: unknown): obj is Promise<T> {
return typeof (obj as Promise<T>).then === "function";
}
const a: A = {
x: () => {}
};
const promiseA = Promise.resolve(a);
function doSomething<T = A | Promise<A>, R = T extends Promise<A> ? Promise<A> : A>(arg: T): R {
if (isPromise<A>(arg)) {
const type: Promise<A> = arg;
return Promise.resolve(a) as R;
} else {
const type: A = arg;
return a;
}
}
function doSomething2(arg: A | Promise<A>): void {
if (isPromise<A>(arg)) {
const type: Promise<A> = arg;
} else {
const type: A = arg;
}
}
const anA: A = doSomething(a);
const aPromiseA: Promise<A> = doSomething(promiseA);
const aPromiseB: Promise<A> = doSomething(a);
const anB: A = doSomething(promiseA);