How do I make a Promise typesafe in Typescript?

Viewed 335

Promises seem to be kind of type-unsafe in Typescript. This simple example shows that resolve accepts undefined, whereas Promise.then seems to infer the argument to be non-undefined:

function f() {
  return new Promise<number>((resolve) => {
    resolve(undefined)
  })
}

f().then((value) => { 
  console.log(value+1)
})

(tried in my current project an on http://www.staging-typescript.org/play).

Apparently, Typescript infers the type of value to be number, instead of number | PromiseLike<number> | undefined.

This may be a current Typescript issue, but...

What is an appropriate workaround? I'd like the compiler to warn me that value may be undefinded!

A very simple solution could be to write

f().then((value:number | undefined) => { 
  console.log(value+1) // now I have: Object is possibly 'undefined'
})

but that requires me to actively think about the problem at every call site.

EDIT (current status): Following the solution given by @JerMah, I wrapped the Promise creation in a generic function:

function makePromise<T>(executor: (resolve: (value: T) => void,
                                   reject: (reason?: any) => void) => void)
{
  return new Promise<T>(executor);
}
2 Answers

You could manually set the signature of the resolve function. That way you cannot pass it undefined.

function f() {
  return new Promise<number>((resolve: (arg0: number) => void) => {    
    resolve(undefined); // Argument of type 'undefined' is not assignable to parameter of type 'number'.
  });
}

TypeScript playground

Unfortunately, this isn't possible with current TypeScript. However, at the cost of a little more verbosity, you can change your code to something like this:

const iReturnUndefined = () => undefined

function f() {
    return new Promise<number>((resolve) => {
        const resolvedVal: number = iReturnUndefined() // Type 'undefined' is not assignable to type 'number'.

        resolve(resolvedVal)
    })
}

TypeScript playground

Related