KHW1031
KHW1031

Reputation: 136

When returning Promise then, but getting `Property 'then' does not exist on type 'Promise<number>'`

I am trying to make function that returns Promise or Normal Value.

type Flow1 = <T, U>(a: T | Promise<T>, f: (a: T) => U) => U | Promise<U>

export const flow1: Flow1 = (a, f) => (a instanceof Promise ? a.then(f) : f(a))

flow1(Promise.resolve(4), (n) => n ** 2).then(console.log)

// Property 'then' does not exist on type 'number | Promise<number>'

But I get error when chaining then to the function. I have no idea what is wrong with this typing.

Added

export function flow1<T, U>(a: T, f: (a: T) => U): U {
  return f(a)
}
export function flow2<T, U>(a: Promise<T>, f: (a: T) => U): Promise<U> {
  return a.then(f)
}

flow1(1, (n) => n ** 2)
flow2(Promise.resolve(1), (n) => n ** 2).then(console.log)

Okay is there any way to overload with same function name? :(

Upvotes: 2

Views: 885

Answers (1)

CertainPerformance
CertainPerformance

Reputation: 371019

Although the flow1 function can, inside it, distinguish the difference between an a argument that's a Promise and a plain value, TS doesn't allow the inference to propagate outside.

You'll have to examine the return value to see if you can call .then on it:

type Flow1 = <T, U>(a: T | Promise<T>, f: (a: T) => U) => U | Promise<U>

export const flow1: Flow1 = (a, f) => (a instanceof Promise ? a.then(f) : f(a))

const result = flow1(Promise.resolve(4), (n) => n ** 2);
if (result instanceof Promise) {
  result.then(console.log);
}

You could also use overloading, but it involves quite some boilerplate:

type Flow1 = {
    <T, U>(a: T, f: (a: T) => U): void;
    <T, U>(a: Promise<T>, f: (a: T) => U): Promise<U>;
};
const flow1: Flow1 = <T, U>(a: T | Promise<T>, f: (a: T) => U) => (a instanceof Promise ? a.then(f) : f(a));
flow1(Promise.resolve(4), (n: number) => n ** 2).then(console.log)

Upvotes: 2

Related Questions