Search code examples
javascriptfirebasetestingdefault-valuedestructuring

Default Value in Destructured Function Parameter Causes ReferenceError


I needed to set a default value for db in my CRUD functions for testing purposes and encountered a strange behaviour, I could not figure out yet. Consider the following code:

import { db } from './firebase'

function getUsers({ db = db }) {
  try {
    return db
    ...

Now, when I use the function in my tests, there is no problem, since I invoke the function in my test file with a test db. But the real app should be able to fall back on the default value and call the function without any params. But here, I encounter the error: ReferenceError: can't access lexical declaration 'db' before initialization. I have no idea why this happens.

I found a workaround by renaming the parameter. But still, I would really love to know what is happening here. Anyone have an idea?

Workarond:

import * as firebase from './firebase'

function getUsers({ db = firebase.db }) {
  try {
    return db

Solution

  • That's the way scope works in function declaration parameter lists. The scope of the default argument value context includes the parameter list itself (well, the ones already declared). Thus the db parameter shadows the relatively global symbol from the import.

    You could also workaround the problem by changing the parameter name:

    function getUsers({database = db})
    

    The scope works that way so that it's possible to use parameters earlier in the parameter list in expressions for parameters later in the list:

    function something(a, b = a + 1)
    

    Calling that function like something(0) would set b to 1.

    Oh, and re-reading your question, initializing a parameter to itself doesn't work because, well, it doesn't make sense; if the parameter isn't there in a function call, then it's undefined, so having the default value be undefined explicitly is incorrect.