How to handle functions with default values?

Let’s assume that in your daily work, you often write functions with default parameter values. For example, suppose you’re building a function to display temperature, with the default unit set to degrees Celsius (°C).

const displayTemperature = () => {
  console.log('Temperature is 20°C')
}

displayTemperature() // Temperature is 20°C

Great, we have a starting point where our function displays the temperature.

Now, let’s add a dynamic parameter to specify the temperature value. This parameter will be of type number.

const displayTemperature = (
  temperature: number
): void => {
  console.log(`Temperature is ${temperature}°C`)
}

displayTemperature(20) // Temperature is 20°C

The function above allows us to easily display the temperature in various parts of our application by simply passing the temperature value.

Since our application is being integrated with numerous third-party tools, we should start supporting additional units of measurement, such as Fahrenheit (°F).

We can meet this requirement by adding another parameter to our function.

const displayTemperature = (
  temperature: number, 
  unit: string
): void => {
  console.log(`Temperature is ${temperature}${unit}`)
}

displayTemperature(20, '°C') 
// Temperature is 20°C
displayTemperature(20, '°F') 
// Temperature is 20°F

However, we’re not entirely certain if the second parameter of our function will be utilized by older systems we’ve integrated with, as they might assume no changes are needed in our system. To address this, we can assign a default value of °C to the unit parameter. This approach ensures compatibility with older functions while also supporting new usage scenarios.

const displayTemperature = (
  temperature: number, 
  unit: string = '°C'
): void => {
  console.log(`Temperature is ${temperature}${unit}`)
}

displayTemperature(20) 
// Temperature is 20°C
displayTemperature(20, '°C') 
// Temperature is 20°C
displayTemperature(20, '°F') 
// Temperature is 20°F

As our application continues to grow, we’ve received a new requirement for the temperature display feature: it now needs to include location information (latitude and longitude), the device name, and the MAC address. As mentioned in a previous post on Suggestions for writing typescript code, adding all these parameters individually can become cumbersome.

The best solution is to refactor our function to accept a single parameter in the form of an object.

interface Information {
  temperature: number
  unit: string
}

const displayTemperature = (
  info: Information
): void => {
  const { temperature, unit } = info
  console.log(`Temperature is ${temperature}${unit}`)
}

displayTemperature({ temperature: 20, unit: '°C' }) 
// Temperature is 20°C
displayTemperature({ temperature: 20, unit: '°F' }) 
// Temperature is 20°F

We’ve refactored the function to accept an object and created a model named Information around it, but we haven’t added default values yet.

To add default values in this setup, we can deconstruct the object within the function’s parameters and assign default values directly during the deconstruction.

interface Information {
  temperature: number
  unit?: string
}

const displayTemperature = ({
  temperature,
  unit = '°C'
}: Information): void => {
  console.log(`Temperature is ${temperature}${unit}`)
}

displayTemperature({ temperature: 20}) 
// Temperature is 20°C
displayTemperature({ temperature: 20, unit: '°C' }) 
// Temperature is 20°C
displayTemperature({ temperature: 20, unit: '°F' }) 
// Temperature is 20°F

Personally, I prefer this approach.

So far, we’ve rewritten the function to support an extended set of values. Let’s now add the location, device name, and MAC address to it.

Remember, the goal is to support default values while allowing them to be overridden. For example, the location defaults to latitude 48.137154 and longitude 11.576124, the device name is always “Device”, and the MAC address is required and varies.

interface Information {
  temperature: number
  mac: string
  unit?: string
  address?: {
    latitude?: number
    longtitude?: number
  }
  name?: string
}

const displayTemperature = ({
  temperature,
  mac,
  unit = '°C'
  name = 'Device',
  address = {
    latitude: '48.137154',
    longtitude: '11.576124'
  }
}: Information): void => {
  console.log(
    `Temperature for device: ${name} with mac: ${mac}`
  )
  console.log(
    `Temperature measurements is ${temperature}${unit}`
  )
  const { latitude, longtitude } = address
  console.log(
    `Location is lat: ${latitude} & lng: ${longtitude}`
  )
}

displayTemperature({ 
  temperature: 20, 
  mac: '00:1b:63:84:45:e6'
}) 
// Temperature for device: 
// Device with mac 00:1b:63:84:45:e6
// Temperature is 20°C
// Location is lat: 48.137154 & lng: 11.576124

Lets try to override location from the code above:

displayTemperature({ 
  temperature: 20, 
  mac: '00:1b:63:84:45:e6',
  address: {
    latitude: '47.137154',
    longtitude: '19.576124'
  }
}) 
// Temperature for device: 
// Device with mac 00:1b:63:84:45:e6
// Temperature is 20°C
// Location is lat: 47.137154 & lng: 19.576124

But what if you want to change just the latitude?

displayTemperature({ 
  temperature: 20, 
  mac: '00:1b:63:84:45:e6',
  address: {
    latitude: '47.137154',
  }
}) 
// Temperature for device: 
// Device with mac 00:1b:63:84:45:e6
// Temperature is 20°C
// Location is lat: 47.137154 & lng: undefined

Uh-oh. Something is definitely wrong. When we override the default value for the address, the code assumes we know what we’re doing. If we don’t pass a value for longitude, it ends up being undefined. How can we fix this?

const displayTemperature = ({
  temperature,
  mac,
  unit = '°C'
  name = 'Device',
  address
}: Information): void => {
  console.log(`
    Temperature for device: ${name} with mac: ${mac}`
  )
  console.log(
    `Temperature measurements is ${temperature}${unit}`
  )
  const { latitude, longtitude } = {
    latitude: '48.137154',
    longtitude: '11.576124',
    ...address
  }
  console.log(
    `Location is lat: ${latitude} & lng: ${longtitude}`
  )
}

Now if we do the same as previous step with just passing latitude everything will work as expected.

displayTemperature({ 
  temperature: 20, 
  mac: '00:1b:63:84:45:e6',
  address: {
    latitude: '47.137154',
  }
}) 
// Temperature for device: 
// Device with mac 00:1b:63:84:45:e6
// Temperature is 20°C
// Location is lat: 47.137154 & lng: 11.576124

This approach allows us to be flexible with our parameters.

Keep pushing forward and savor every step of your coding journey.