Home > Software engineering >  Argument of type '() => Promise<string>' is not assignable to parameter of type &
Argument of type '() => Promise<string>' is not assignable to parameter of type &

Time:02-24

I'm defining a function that requires a asynchronous function as a parameter:

async function handle(def: Promise<string>) {
    // ...
    const data = await def;
    console.log(`data equals: ${data}`)
}

I can succesfully execute this by passing a promise.

handle(new Promise(async (res, rej) => {
    const data = await Promise.resolve("some data")
    if (data == "invalid")
        return rej("data is invalid")
    res(data)
}))

I need the inner-function to be async, since I need to perform awaits inside. However, I dislike the async in the promise and read online that its considered an anti-pattern.

I thought it was a better idea to get rid of the promise and use a basic async function:

handle(async () => {
    const data = await Promise.resolve("some data")
    if (data == "invalid")
        throw "data is invalid"
    return data
})

But the TS compiler raises the error:

Argument of type '() => Promise<string>' is not assignable to parameter of type 'Promise<string>'. ts(2345)

I thought that Promises and async functions are somewhat interchangable. I read that async functions always return a promise. Apperantly I am not interpreting this correctly, but I'm unsure what the error is telling me.

I hope the problem I am sketching is clear. It would be greatly appreciated if someone could clarify the error or give suggestions on how to implement this in the desired way. Big thanks!

CodePudding user response:

your function signature seems to be incorrect. you are defining the parameter to be a Promise<string>, while you're really willing it to be () => Promise<string>.

async function handle(def: () => Promise<string>) {
    // ...
    const data = await def();
    console.log(`data equals: ${data}`)
}

CodePudding user response:

In general, the time to use the Promise constructor in a situation like this is right when you call a callback-based function that you want to promisify. But here, it doesn't look like there's anything to promisify, so the Promise constructor doesn't really help.

If

I need the inner-function to be async, since I need to perform awaits inside.

You can have an immediately invoked async IIFE - yes, using an async callback for the Promise constructor wouldn't be safe, because it wouldn't handle errors.

handle((async () => {
    const data = await Promise.resolve("some data")
    if (data == "invalid")
        throw "data is invalid";
    return data
})())

The other option is to use .then - .then is interchangeable with await in many situations:

handle(
  Promise.resolve("some data")
    .then((data) => {
        if (data == "invalid")
            throw "data is invalid";
        return data;
    })
);

CodePudding user response:

An aside, you can replace

 const data = await Promise.resolve("some data")

with

 const data = await "some data"

but anyway...you are on the right track, and your head is in the right place, but the equivalent would be:

handle(() => new Promise(async (res, rej) => {
    const data = await Promise.resolve("some data")
    if (data == "invalid")
        return rej("data is invalid")
    res(data)
}))

because an async function is a function that always returns a promise, but it is not a promise.

  • Related