Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type 'Promise<number>' is not assignable to type 'number'

I'm trying to return number from a promise: the function getActualId call from chrome.local.storage and returns a promise:

function getActualId(){
    return new Promise(function (resolve) {
        chrome.storage.sync.get({
            userId: true
        }, function (userId) {
            resolve(userId.userId);
        });
    });
}

this function gets the right value but when I call it from another function I keep getting the the getId function return a Promise<number> and not a promise.

async function getId(){
    let id:number = 0;
    await getActualId().then( function(userid:number){
        id =  userid;
    })
    return id
}

How can I get the real value of id from getId and not a promise<number>?

like image 617
j.her Avatar asked Mar 10 '19 10:03

j.her


1 Answers

You almost never use then in an async function.¹ The point of async functions is you can use await instead. In your case, you want to assign the result of await getActualId() to id:

async function getId(){
    let id:number = await getActualId();
    return id;
}

(Although it's not clear why that function would need to exist, it's just a wrapper around getActualId.)

There's a problem with getActualId, though, and if we fix that we don't need a type annotation on id in getId: getActualId is missing its return type annotation, so it implicitly returns Promise<any>. If it's returning Promise<number>, you need to say that:

function getActualId(): Promise<number> {
    return new Promise(function (resolve) {
        chrome.storage.sync.get({
            userId: true
        }, function (userId) {
            resolve(userId.userId);
        });
    });
}

Example in the playground:

function getActualId(): Promise<number> {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve(Math.floor(Math.random() * 100));
        }, 100);
    });
}
async function getId() {
    let id = await getActualId();
    return id;
}

If you hover id in getId, you'll see that TypeScript knows it's a number thanks to the signature of getActualId, so we don't need the type annotation as TypeScript can infer it.


¹ By "almost never" I mean genuinely almost never. The only example I can think of is if you have a bunch of operations to do in parallel (so you're using Promise.all) and you need to do a transform on the result of one of them. Then you might do this:

const [first, second, third] = await Promise.all([
   firstOp(),
   secondOp().then(value => value.toUpperCase()),
   thirdOp()
]);

since using await on secondOp would delay the start of thirdOp (while the above doesn't).

like image 64
T.J. Crowder Avatar answered Oct 31 '22 23:10

T.J. Crowder