Hari Warshan
Hari Warshan

Reputation: 153

Variable is used before its assignment typescript

I have a set of async tasks which is independent of each other. I have two questions, when considering the below code.

const parallelTasks: any = []    
let email:string

//parallelTasks.push(otherPromises)

const PromiseTask1 = new Promise(async(resolve,reject)=>{
         //some code
         email = await GetEmail(connection)
         resolve('')
    })
 parallelTasks.push(PromiseTask1)
 
 // Scenario 1
 await Promise.all(parallelTasks)
 console.log(email) //this is giving me lint error "variable email is used before assignment"
  
 // Scenario 2
 Promise.all(parallelTasks).then(()=>{
     console.log(email) //this is working fine
 })

if i declare just like below, its not showing me any lint error. my questions are

let email: any
  1. Is any includes Promise type as well?
  2. Just consider am using scenario 1, Is await Promise.all() blocks the execution of all its below code, if yes, then I should not be getting the lint error when i used email: string. if no then, I Shouldnt be getting the value of email in console right. but surprisingly I got the resolved value. what am missing here?

Upvotes: 2

Views: 906

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074008

Re #1

Yes, any includes any type, including Promise.

Re #2

I think you mean you're getting:

Variable 'email' is used before being assigned.(2454)

from the line using email in code similar to this:

(async () => {
    const parallelTasks: any = []    
    let email:string

    //parallelTasks.push(otherPromises)

    const PromiseTask1 = new Promise(async(resolve,reject)=>{
            //some code
            email = await GetEmail(/*connection*/)
            resolve('')
        })
    parallelTasks.push(PromiseTask1)
    
    // Scenario 1
    await Promise.all(parallelTasks)
    console.log(email) //this is giving me error 
})();

async function GetEmail() {
    return "foo";
}

Playground link

If so, it's just that you've hit a limit on TypeScript's ability to determine that email has been assigned to. You're right, it has been assigned to, but it's done too indirectly for TypeScript to see it.

There are at least two ways to deal with that.

The first way

You could use the result of Promise.all, by removing your extra unnecessary new Promise call and using GetEmail directly:

(async () => {
    const parallelTasks: any = [];

    parallelTasks.push(GetEmail(/*connection*/))
    
    const [email] = await Promise.all(parallelTasks);
    console.log(email); // No error now
})();

async function GetEmail() {
    return "foo";
}

Playground link

You'd adjust the destructuring to allow for the results of the other tasks you're putting into parallelTasks. For instance:

parallelTasks.push(task1());
parallelTasks.push(task2());
parallelTasks.push(GetEmail(connection));
parallelTasks.push(task4());

then it might be:

const [result1, result2, email, result4] = await Promise.all(paralleltasks);

or if you didn't need the others, just put GetEmail(connection) in at the front and use the original destructuring above (const [email] = ...).

The second way

You can tell TypeScript that you know email will be definitely assigned before you use it, using the definitely-assigned assertion (!):

let email!:string;
//       ^

Upvotes: 4

Related Questions