What are your thoughts on changing a function argument within the function itself?

Recently, my coding style came under scrutiny for the following snippet:

export const myFunction = (myArgument: TypeOfObject[]) => {
  if (!myArgument) {
    myArgument = [];
  }
  // do something with myArgument
}

In TypeScript, it seems that myFunction receives a pointer called myArgument by value. If this pointer is pointing to undefined, I simply reassign it to an empty array. Otherwise, it remains unchanged. Therefore, neither the object pointed to nor the pointer itself are being altered within the caller's context.

This approach has been criticized as poor form, with the suggestion of an alternative method:

export const myFunction = (myArgument: TypeOfObject[]) => {
  let myArgumentSecond: TypeOfObject[];
  if (!myArgument) {
    myArgumentSecond = [];
  } else {
    myArgumentSecond = [...myArgument];
  }

  // do something with myArgumentSecond (instead of with myArgument)
}

What are your thoughts on this? Do you believe the second version is truly superior?

Despite being in TypeScript, I consider this a broader programming question and fail to grasp the issue with the initial implementation.

Answer №1

// In a TypeScript project, default argument values are recommended for clarity.

export const myFunction1 = (myArgument: TypeOfObject[] = []) => {
  // Perform operations with myArgument
  myArgument
  // ^? (parameter) myArgument: TypeOfObject[]
}
// It's important to specify whether the function can accept non-array arguments.

export const myFunction2 = (myArgument?: TypeOfObject[] | null | undefined) => {
  myArgument ??= [];
  myArgument
  // ^? (parameter) myArgument: TypeOfObject[]
}

// When using type casting in TypeScript, consider assigning the result to another variable.
export const myFunction3 = (a: number | string) => {
  a = Number(a) % 3 as 0 | 1 | 2
  ;; a
  // ^? (parameter) a: number
  let b = Number(a) % 3 as 0 | 1 | 2
  //  ^? let b: 0 | 1 | 2
}

interface TypeOfObject {};

If you want to restrict argument assignment, refer to the no-param-reassign rule in ESLint documentation. Follow the guidance of your linter regarding modifying arguments within functions.

Answer №2

In my perspective, the main distinction between your implementation and the proposed solution lies in the fact that you guarantee not to alter the argument. Essentially, whatever argument is passed to the function will remain unchanged (although modifications can still be made to items within the array). The superiority of one approach over the other is subject to debate and the underlying intention. For instance:

function sortInplace(x) { // Indicates a desire to mutate
  x.sort()
}

function sortNotInplace(x) {
  return [...x].sort()
}

a = [4,3,2,1]

sortInplace(a) // mutates 'a', making this function impure

console.log(a) // [1,2,3,4]

b = [4,3,2,1]
c = sortNotInplace(b) // duplicates 'b', sorts the duplicate, and returns the sorted copy, thus maintaining purity

console.log(b) // [4,3,2,1]
console.log(c) // [1,2,3,4] 

It is preferable to have functions that are deemed "pure", indicating they do not modify anything externally, as opposed to "impure" functions which can lead to elusive bugs.

The downside of aiming for purity is typically a reduction in runtime performance since more copying is often required. However, in many scenarios, the performance impact can be minimal. The provided code will generate an entirely new array. If the initial array is sizable, the computer must allocate resources to create a new large array, leading to potential inefficiencies.

These thoughts are solely my own and may not align with all readers:

I find your initial snippet acceptable (it aligns with my preference), with the crucial aspect being awareness of whether the input is being mutated or not, and appropriately signaling if mutation is intended, or adjusting the function if non-mutation is desired. It is also important to take into account any agreed-upon coding style among colleagues. If the suggested code reflects the consensus among peers, adhering to it would be advisable (particularly within a software development team context). The suggested code explicitly communicates that there will be no alterations to the input array (though in cases of small and easily understandable functions, this might be apparent regardless).

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

difficulty with closing nested Mat-dialogBoxes

I am facing an issue with passing data between multiple dialog boxes in my parent raster component. I have a parent raster component that opens the first dialog box, followed by a second dialog box. My goal is to pass data from the last dialog box back to ...

How to configure mat-sort-header in Angular Material for mat-table

My current table is created using Angular Material: <mat-table *ngIf="!waiting" class="table-general table-summary" #table [dataSource]="dataSource" matSort> <mat-header-row class="header_row" *matHeaderRowDef="headerKeys"></mat-header ...

Cannot trigger event ascn.onchange does not exist as a function

Need to trigger the onChange function and pass parameters within it. Here's what I have tried: setTimeout(function() { document.getElementById(input.key)?.onchange({}) }, 200); Encountering the following error message: cn.onchange is not a function ...

How can I arrange a table in Angular by the value of a specific cell?

Here's the current layout of my table: Status Draft Pending Complete I'm looking for a way to sort these rows based on their values. The code snippet I've been using only allows sorting by clicking on the status header: onCh ...

What steps can be taken to eliminate redundancy in this code and improve its efficiency?

Here I have two methods, create and update, that send data to an API. I am looking to enhance the createUser and updateUser methods as they are very similar. Additionally, if you have any suggestions on a better way to directly set the id property as null ...

Passing a click event to a reusable component in Angular 2 for enhanced functionality

I am currently working on abstracting out a table that is used by several components. While most of my dynamic table population needs have been met, I am facing a challenge with making the rows clickable in one instance of the table. Previously, I simply ...

Observables do not provide any results when used in a pipe with an image src

I recently created a custom pipe for the image src in my application: It is applied to selectors like this: <img [src]="myobject?.URL | secure" /> Here's the code snippet for the pipe: import { Pipe, PipeTransform } from '@angular/c ...

Angular - Clear the selection of <select><option> if I opt out of accepting the change

I have created a dropdown menu using HTML <select> and <option> tags, along with a JavaScript function that triggers a confirmation dialogue when an option is selected. The confirmation offers a simple choice between "yes" or "no." If the user ...

Tips on transferring a child Interface to a parent class

Here is my code snippet: LocationController.ts import {GenericController} from './_genericController'; interface Response { id : number, code: string, name: string, type: string, long: number, lat: number } const fields ...

Instead of relying on Vue TypeScript, we are leveraging IntelliJ with TypeScript 5.0.3 to compile our Vue project

My current version of IntelliJ IDEA is 2023.1 (Ultimate Edition) Build #IU-231.8109.175, released on March 28, 2023. I am facing an issue where my project fails to compile using "Vue TypeScript", resulting in some type mismatches being overlooked. In the ...

Refresh an array prior to subscribing in Angular 2

When attempting to apply multiple filters in a quick session, I am encountering an issue where the previous data persists in the array alongside the new data. How can I effectively remove the previous data? component.ts ngOnInit() { this.vehicleAttribu ...

Creating a structure within a stencil web component

In my current project, I am utilizing Stencil.js (typescript) and need to integrate this selectbox. Below is the code snippet: import { Component, h, JSX, Prop, Element } from '@stencil/core'; import Selectr from 'mobius1-selectr'; @ ...

Exploring Blob functionality in TypeScript?

I defined a global Blob object: declare global { interface Blob { prototype: Blob; new (name: string, url: string): Blob; } } It is functioning correctly in this code snippet: export const blobToFile = (blob: Blob) => { let file: File | n ...

How can Karma unit tests with Jasmine in a TypeScript Node project accurately measure code coverage, even with external dependencies?

We have a unique situation with the code coverage of our project involving a node dependency. It's important to note that the npm dependency source code is actually part of our project, as we are responsible for its development and publication. Here&a ...

The correlation between subject matter and the workflow of resilience

I am seeking clarity on how Subjects behave when used with the resiliency operators, specifically retry and retryWhen. The code samples below may differ slightly from the JSBin examples as I have used arrow functions and types for better understanding. Th ...

Developing a universal SDK wrapper for Firebase services (Firestore, Cloud Storage, and additional functionalities)

Currently, I am on the quest to discover an abstraction that can facilitate the seamless operation of Firebase products (specifically Firestore, Storage, and Analytics) across any platform (be it React Native, React, or Node.js). While considering the REST ...

Angular: Implementing a Dark and Light Mode Toggle with Bootstrap 4

Looking for suggestions on the most effective way to incorporate dark mode and light mode into my bootstrap 4 (scss) angular application. Since the Angular cli compiles scss files, I'm not keen on the traditional method of using separate css files for ...

Leveraging cloud functions on Firebase for maximum efficiency

Question: Do you require a backend language when using Firebase Cloud Functions, or can TypeScript alone suffice for coding tasks like creating a matchmaking system? Response: There seems to be some uncertainty on the matter even from ChatGPT himself. Is ...

Handling the onSelect Event in React Bootstrap Dropdown using TypeScript

Using a combination of React, TypeScript, and react-bootstrap, I have created a dropdown list: ipc_handleSelect = (eventKey: any, event: any) => { } render() { return ( <Dropdown> <Dropdown.Toggle>Text</Dropdown. ...

Mapping a response object to a Type interface with multiple Type Interfaces in Angular 7: A step-by-step guide

Here is the interface structure I am working with: export interface ObjLookup { owner?: IObjOwner; contacts?: IOwnerContacts[]; location?: IOwnerLocation; } This includes the following interfaces as well: export interface IObjOwner { las ...