Push variable declaration into initial value

Inlines a variable that is initialized with another variable into the declaration of that variable.

Push variable declaration into initial value

When a variable is initialized with a second variable, and that second variable is only used in that initialization, you can use the variable instead of the second variable and remove the indirection.

For example, here variable can be pushed in the definition of secondVariable:

const secondVariable = someSource();
const variable = secondVariable;

becomes

const variable = someSource();

Why is this refactoring helpful?

The refactoring helps remove unnecessary indirection. It is particularly useful for pushing destructuring into parameters and catch clauses:

function f(aParameter) {
  const { variable1, variable2 } = aParameter;
  doSomething(variable1, variable2);
}

becomes

function f({ variable1, variable2 }) {
  doSomething(variable1, variable2);
}

What do I need to consider?

The variable type can change

When the two variable declarations have different types, and the first declaration declares several variables, the broader type needs to be used.

This means that const can be changed into let or var, and let can be changed into var. The change to let means that previously constant variables now can be modified, and the change to var can change the scope of the variable.

Consider the following example:

const intermediateVariable = someSource(),
      anotherVariable = anotherSource();
var aVariable = intermediateVariable;

Here, pushing up aVariable and removing intermediateVariable requires changing the const to var to support the scope of aVariable. This refactoring changes the scope of anotherVariable as well.

Similarly, pushing a const variable into a function or catch clause parameter means it will become modifiable.

Exports can be affected

When one of the two variable declarations is exported, the refactoring can impact the module's exports.

For example,

export const obj = something;
const aVariable = obj;

becomes

export const aVariable = something;

This change impacts the module's exports, and you might need to update references to it inside other modules as well. If the exports are library exports, this could be a breaking change.

The execution order can change when inlining destructuring

Destructuring can have side effects when e.g., getters are invoked. When pushing up a variable into its definition, it can affect the execution order.

Here is an example:

const executed = [];

class Example {

    constructor(name) {
        this.name = name;
    }

    get field() {
        executed.push(`${this.name} - field`);
        return "field";
    }

    get innerExample() {
        executed.push(`${this.name} - inner example`);
        return new Example("inner");
    }
}

const { innerExample: intermediateVariable, field } = new Example("outer");
const { field: innerField } = intermediateVariable;

console.log(executed); // [ 'outer - inner example', 'outer - field', 'inner - field' ]

After the refactoring, the bottom part becomes:

const { innerExample: { field: innerField }, field } = new Example("outer");

console.log(executed); // [ 'outer - inner example', 'inner - field', 'outer - field' ]

inner - field is now added to executed before outer - field.

The TypeScript type can be narrowed

When the intermediate variable is part of a destructuring expression, the type information from the inlined variable is dropped. This can lead to a narrowing of the type.

const { value: intermediateVariable }: {value: "123"} = {
  value: "123"
}

const aVariable: string = intermediateVariable;

becomes

const { value: aVariable }: {value: "123"} = {
  value: "123"
}
// now aVariable has type "123" and not string

Configuration

Related Code Assists

Learn More

Available In