Type checking in separate function not working in typescript

Viewed 496

I'm validating type of parameter in separate function but still it is giving the following Error-

Argument of type 'string | undefined' is not assignable to parameter of type 'string'. Type 'undefined' is not assignable to type 'string'.

The code is like this-

function paramValidator(param?: string){
  if(param===undefined){
    throw new Error('parameter missing');
  }
}
function xyz(a: string){
  console.log(a);
}

function abc(a?: string){
  try{
    paramValidator(a);
    // Working Fine
    // if(a===undefined){
    //   throw new Error('parameter missing');
    // }
    xyz(a);  //This line is throwing error
  }
  catch(e){
    console.log('Error');
  }
  
}

I want to put validation logics in a separate function for cleaner code. How to enforce that the parameter is defined after validation?

6 Answers

You can return true if the param is actually a string and use this as condition

function paramValidator(param?: string): param is string {
  if(param===undefined){
    throw new Error('parameter missing');
  }
  return true;
}

function xyz(a: string){
  console.log(a);
}

function abc(a?: string){
  try{
    if (paramValidator(a)) {
        xyz(a);
    }
  }
  catch(e){
    console.log('Error');
  }
}

If you are using Typescript 3.7+, use you use assertion functions. The change is minimal; you simply add an asserts condition to your method signature:

function paramValidator(param?: string): asserts params is string {

Any time after you have called this function, Typescript will recognise that the value of param should be string, and you won't get the error.

Playground link

The solution is to use xyz(a!) as it will enforce that the parameter is defined. We have already validated the type in another function, so we do not need to do that while calling the function.

It is because of you using? optional operator which tells the function that it might be available during the execution that is based on whether you send it in the abc function or not. So, it becomes undefined till the time method is not called with that param.

For such cases, you assign a fallback i.e default parameters values in the methods. I'm not sure why you need to have validator if you can default assign values, it is good to have empty string instead something is undefined.

function paramValidator(param?: string){
  if(param===undefined){
    throw new Error('parameter missing');
  }
}
function xyz(a: string){
  console.log(a);
}

function abc(a: string = ''){
  try{
    paramValidator(a);  // now you don't need to call it 
    // Working Fine
    // if(a===undefined){
    //   throw new Error('parameter missing');
    // }
    xyz(a);  //This line is throwing error
  }
  catch(e){
    console.log('Error');
  }
  
}

Also, when you have objects and properties associated with it try to check their properties using ?? to set null|undefined properties to default values, so you won't expect any undesirable behaviour in the application.

I think putting your try catch block inside a if block will fix the error .Because param validator waiting a string and you are passing a possible undefined or string value to it .

function abc(a?: string){
if(a){
    try{
        paramValidator(a);
        // Working Fine
        // if(req.a===undefined){
        //   throw new Error('parameter missing');
        // }
        xyz(a);  //This line is throwing error
      }
      catch(e){
        console.log('Error');
      }
    }
  
}

As Aprova Chikara described, It was a good explanation and outstanding solution for your problem. But if you would like insist in your code and wouldn't change its structure yet, You can keep your base code as follows with 2 tiny changes:

function paramValidator(param?: string):string{
   if(param===undefined){
       throw new  Error("parameter missing");
   }
   return param;// 1
}

function xyz(a: string){
   console.log(a);
}

function abc(a?: string){
  try{
    a = paramValidator(a) // 2
    xyz(a);  //Now, this line is not throwing error!
  }
  catch(e){
    console.log('Error');
  } 
}
Related