Stephan Olsen
Stephan Olsen

Reputation: 1825

Getting the return type of resolved promise?

I want to create a variable with some default values, that is an extended interface of the resolved return type from a promise. My function would be something like:

function getAge(): Promise<number> {
  return new Promise((resolve) => {
  resolve(42)
  })
}

My variable with default values would be:

let user: { name: string, age: number } = { name: "", age: 0 }

I've tried using the ReturnType<>, however I can only seem to get the return type Promise<number>, when I just want number returned.

Upvotes: 14

Views: 7591

Answers (2)

JCat
JCat

Reputation: 335

Update in Typescript 4.5

You can use new Awaited type

for example:

let bar: Awaited<ReturnType<typeof foo>>

This works the same as the UnboxPromise example from Titian Cernicova-Dragomir, but Awaited can deploy Promise recursively.

Old Answer

I liked Titian Chernikov-Dragomir's response (example `UnboxPromise').

Alternatively, you can define a type similar to ReturnType, only with the return value as a promise.

type ReturnPromiseType<T extends (...args: any) => Promise<any>> = T extends (...args: any) => Promise<infer R> ? R : any;

Example:

// Our declared type
type ReturnPromiseType<T extends (...args: any) => Promise<any>> = T extends (...args: any) => Promise<infer R> ? R : any;

// Let's imagine that we do not have direct access to this type (a typical case when using external libraries)
interface Foo {
    a: string
}

// Here we already have access to the function, but we still don't have access to the return type.
function foo(): Promise<Foo> {
    return Promise.resolve({
        a: "abc"
    })
}

(async () => {
    let bar: ReturnPromiseType<typeof foo> // returns our interface/type Foo
    let baz: any // any by default

    bar = await foo();
    baz = await foo();

    // typeof bar
    // in IDE shows - let bar: Foo
    // typeof bar.a
    // in IDE shows - (property) Foo.a: string
    
    //typeof baz
    // in IDE shows - any
    //typeof baz.a
    // in IDE shows - any
})();

in Typescript Playground

Upvotes: 21

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250106

You can use a conditional type to extract the value type of a promise:

function getAge(): Promise<{ name: string, age: number }> {
  return new Promise((resolve) => {
  resolve({ name: "", age: 42 })
  })
}

type UnboxPromise<T extends Promise<any>> = T extends Promise<infer U> ? U: never;

let user: UnboxPromise<ReturnType<typeof getAge>> = { name: "", age: 0 }

Read more about conditional types here

Upvotes: 9

Related Questions