Passing optional and default parameters in a function is a common practice used by programmers developing not only in TypeScript or JavaScript but any programming language. In this tutorial, we are going to explain how to use them in TypeScript, compare the TypeScript syntax with the JavaScript syntax, as well as share some best practices when using default parameters.

How to Use Optional Parameters in TypeScript

If we want to use optional parameters in TypeScript, we can enable it by adding a question mark ? at the end of each parameter of a function. Let’s look at the following example to make things clear.

function updateInfo(id: string, email: string, updatedBy?: string) {
  // check if the email provided is empty
  if (!email) throw new Error('It must provide an email');

  const db = mysql.createConnection({
    host: "localhost",
    user: "yourusername",
    password: "yourpassword",
    database: "mydb"
  });
  
  db.connect(function(err) {
    if (err) throw err;

    // it must update the user's email
    let sql = `
      UPDATE users 
      SET 
      email = ?
     `;
   const queryParams = [email];

    // check if value provided in optional parameter
    if (updatedBy) {
       sql += `, updated_by = ?`;
       queryParams.push(updatedBy);
    }

   // update only one record based on id provided
   sql += `WHERE id = ?`;
   queryParams.push(id);
    
    db.query(sql, queryParams, function (err, result) {
      if (err) throw err;
      console.log(result.affectedRows + " record(s) updated");
    });
  });
}

Notice the parameters of the updatedInfo function in the previous code snippet. It accepts three parameters: id, firstName, and updatedBy. Out of the three parameters, only updatedBy has the question mark ? at the end of the parameters’ definition. Hence, this means updatedBy is the only optional parameter in this function.

Why Using Optional Parameters

Having optional parameters is a neat functionality that allows developers to avoid passing all of the parameters defined in a function. This makes it easier for the logic calling a function to provide only the necessary values required for the main logic of a function to be executed.

On the other hand, it allows a function to hide extra layers of logic complexity. If we revisit the previous snippet of code, the main functionality of the updateInfo function is to update a user’s email. Notice how it is possible to update the updated_by field inside updateInfo when the updatedBy parameter is provided, even though it is not considered a critical part of logic.

Also, notice how the code becomes more complex when adding the logic to update the updated_by field. If we decide to remove the logic to update the updated_by field, which would make the updateBy parameter unnecessary, the updateInfo function would be much simpler and with fewer lines of code as well.

function updateInfo(id: string, email: string) {
  // check if the email provided is empty
  if (!email) throw new Error('It must provide an email');

  const db = mysql.createConnection({
    host: "localhost",
    user: "yourusername",
    password: "yourpassword",
    database: "mydb"
  });
  
  db.connect(function(err) {
    if (err) throw err;

    const sql = `
      UPDATE users 
      SET email = ?
      WHERE id = ?
     `;
    const queryParams = [email , id];

    db.query(sql, queryParams, function (err, result) {
      if (err) throw err;
      console.log(result.affectedRows + " record(s) updated");
    });
  });
}

Comparing JavaScript and TypeScript Usage of Optional Parameters

The functionality of passing optional parameters in both JavaScript and TypeScript is the same. However, their implementation is different. In JavaScript, all parameters are considered optional by default, even if the internal logic of a function depends on some parameters. Let’s look at the following example:

function getCar(id) {
  const db = mysql.createConnection({
      host: "localhost",
      user: "yourusername",
      password: "yourpassword",
      database: "mydb"
  });
  
  return new Promise(function(resolve, reject) {
    db.connect(function(err) {
        if (err) reject(err);
    
        const sql = `
          SELECT * FROM users 
          WHERE id = ?
        `;
        const queryParams = [ id];
    
        db.query(sql, queryParams, function (err, result) {
          if (err) reject(err);
          resolve(result);
        });
    });
  })
}

// it will fail during runtime in JavaScript
getCar();

The getCar function depends on the id parameter to fetch the correct car from the database, if not provided, the function most likely will fail during runtime.

This is a problem in JavaScript as errors cannot be prevented much sooner prior to deploying code to production environments. In other cases, it would create the need for JavaScript developers to pass all parameters even if some are truly optional, for the sake of avoiding errors in runtime due to the lack of parameter values.

TypeScript aims to solve this issue by making all parameters defined in a function required unless the parameter is followed by a question mark ?. Also, it will allow getting much sooner feedback to programmers as code will fail in build time instead of runtime.

// it will fail during build in TypeScript
getCar();

How to Use Default Parameters in TypeScript

If we want to set a default parameter in TypeScript, the parameter must have in the end the equal sign (=) followed by the default value. Let’s look at an example of this implementation:

function logHello(requiredParamater: string, defaultParameter: string = 'foobar') {
  console.log(`${requiredParamater} ${defaultParameter}`);
}

logHello('hello'); // result: 'hello foobar'
logHello('hello', 'andres'); // result: 'hello andres'

Notice how the logHello function can be called with or without defaultParameter.

Why Using Default Parameters

Using default parameters allow you to not worry about providing values of parameters that are repetitive when calling a function in different scenarios while also avoiding to provide all parameters to trigger a function.

If we look back at the first definition of the updateInfo, we defined an optional updatedBy parameter to update the updated_by field of a record whenever the parameter is provided. However, that is not a typical implementation of an update functionality as under real projects we need to track the last user who made updates to a record. Hence, we are going to modify the updateInfo function to always update the updated_by regardless if the updatedBy is provided during its execution.

function updateInfo(id: string, email: string, updatedBy: string = 'admin') {
  // check if the email provided is empty
  if (!email) throw new Error('It must provide an email');

  const db = mysql.createConnection({
    host: "localhost",
    user: "yourusername",
    password: "yourpassword",
    database: "mydb"
  });
  
  db.connect(function(err) {
    if (err) throw err;

    const sql = `
      UPDATE users 
      SET 
      email = ?, 
      updated_by = ?
      WHERE id = ?
     `;
   const queryParams = [email, updatedBy, id];

    db.query(sql, queryParams, function (err, result) {
      if (err) throw err;
      console.log(result.affectedRows + " record(s) updated");
    });
  });
}

Now, everytime any logic of code is calling the updateInfo without the updatedBy parameter, the updated_by field of the record will default to 'admin'.

updateInfo('123id', 'foo@bar.com');

This gives us the flexibility to also set the updated_by field of a record to a different value besides 'admin' whenever it is considered necessary.

updateInfo('123id', 'foo@bar.com', 'andres');

Best Practice When Using Default Parameters

It is recommended to define default parameters after all required parameters are defined. Otherwise, you will be forced to provide a value to the parameter with a default value as other parameters have required values.

Let’s modify the position of the parameters of the logHello function to see how this affects calling this function.

function logHello(defaultParameter: string = 'foobar', requiredParamater: string) {
  console.log(`${requiredParamater} ${defaultParameter});
}

// we no longer can call the logHello function passing only one parameter 
logHello('andres'); // this will fail during build time

// we are forced to provide the two parameters even if one of them has already an
// default value
logHello('andres', 'hello'); // result: 'hello andres'

Notice how defining defaultParameter prior to defining requiredParameter will force us to provide the two parameters when calling the logHello function. Therefore, we won’t be able to avoid passing a value to defaultParameter.

More TypeScript Tips!

There is a list of TypeScript tips you might be interested in checking out.

Conclusion

Using optional and default parameters is a handy functionality to hide additional and repetitive complex logic of code in a function. Using optional parameters in JavaScript differs from how it is used in TypeScript. However, it is recommended to assign default and optional parameters only after required parameters are defined in a function regardless of whether you are using JavaScript or TypeScript.

Did you like this article?

Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.

Author