enapupe
enapupe

Reputation: 17029

Typed Promise changes return type to unknown when `finally` is added

I have a regular promise with a statically typed return type:

export const hasActiveSubscription = (whatEver: string): Promise<string> => 
  new Promise((resolve, reject) => {
    if (true){
      return resolve('imastring')
    }
    return reject(new Error('nope'))
  })

So far so good, but if I add a finally block, it changes the return type to unknown and fails to deliver that string type, e.g.

export const hasActiveSubscription = (whatEver: string): Promise<string> => 
  new Promise((resolve, reject) => {
    if (true){
      resolve('imastring')
    }
    reject(new Error('nope'))
  }).finally(console.info)

Type 'Promise' is not assignable to type 'Promise'.
Type 'unknown' is not assignable to type 'string'.

How can I retain the original return type while keeping the finally block?

If it helps, my actual code has a setTimeout (to be sure this function doesn't take too long to return) and I want to clear the timeout on finally, instead of clearing a timeout on 5 different locations.

Upvotes: 4

Views: 2162

Answers (1)

0Valt
0Valt

Reputation: 10345

If you remove type annotation from the return position of the function signature, you will notice that the actual return type is Promise<unknown>, not the Promise<string> as you expected, which constitutes the first part of the error:

const hasActiveSubscription: (whatEver: string) => Promise<unknown>;

Promise is a generic interface, and its finally method uses the type parameter of the interface in its return type annotation (the sample is from the ES2018 lib):

interface Promise<T> {
    finally(onfinally?: (() => void) | undefined | null): Promise<T>
}

All you need to do is to specify the type of the constructed Promise, and everything will be a-ok:

export const hasActiveSubscription = (whatEver: string) => 
  new Promise<string>((resolve, reject) => {
    if (true){
      resolve('imastring')
    }
    reject(new Error('nope'))
  }).finally(console.info) //no error, Promise<string> is inferred

Playground


Small note - your example has an unmatched bracket in the reject call

Upvotes: 5

Related Questions