Tips for ensuring a method is not invoked more than once with identical arguments

I'm grappling with a challenge in JavaScript (or typescript) - ensuring that developers cannot call a method multiple times with the same argument.

For instance:

const foo = (name: string) => {}


foo("ABC") // ok

foo ("123") // ok

foo ("ABC") // ideally, should prompt an error in the IDE indicating that it was already called with the same value previously

To clarify, I am looking to catch this error during the development process, prior to runtime. My intention is for developers to be notified of any mistakes while coding, prompting the IDE to flag the error.

Is there a way to accomplish this? Perhaps through creating a custom tslint rule?

Edit: If achieving the desired outcome above is not natively supported in JavaScript, then alternatively, a new custom tslint rule could suffice. Rules have the capability to store values and context, which can potentially trigger errors during development time, similar to other linting rules in the IDE.

Is this achievable? How would one go about creating a new lint rule with contextual awareness to address this issue?

Furthermore, I am open to scenarios where foo(x) is utilized and the rule may not recognize the exact value of x or the order in which the function is invoked.

The rule only needs to be intelligent enough to handle basic cases where possible.

Answer №1

One way to handle this issue is by throwing an error at runtime during development:

const usedNames = []

const foo = (name: string) => {
  if (process.env.NODE_ENV === 'development') {
    if (usedNames.includes(name)) throw new Error(`Function already called with ${ name }.`)

    usedNames.push(name)
  }

  ...
}

In non-development builds, the

if (process.env.NODE_ENV === 'development') { ... }
block will be omitted altogether. You can learn more about handling environment variables in webpack here.

Answer №2

Regrettably, neither TypeScript nor JavaScript have the capability to implement this type of feature natively. To my knowledge, there is no built-in mechanism in JavaScript or TypeScript that enables you to impose restrictions at compile-time based on runtime values or usage. These languages are simply not intended to track this kind of behavior.

Typically, a static type checker like TypeScript examines types through static analysis without actually executing or tracing the code. Therefore, TypeScript cannot perform checks that rely on the runtime behavior of the code, such as the sequence or frequency of function calls.

To identify these logical issues early on, unit tests are often a more effective option. You could create a test that verifies if 'foo' throws an error when called with the same argument twice, and then regularly run your tests during development. Another approach could be utilizing a linter or static analysis tool that supports custom rules, although I am unsure if any existing tools can handle this specific scenario.

If you wish to enforce such a rule, your best course of action may be to provide documentation or comments clarifying the requirement, and trust developers to adhere to it manually.

Additionally, it is possible that your situation could benefit from a different pattern or structure. If you frequently encounter the need to prevent developers from invoking a method multiple times with the same argument, it might be worth considering a design that preemptively eliminates that possibility altogether.

Answer №3

You can utilize chaining to sequentially list the arguments that have been used
https://tsplay.dev/WJpZrN

type conform<T, V, E> = T extends V ? T : { error: E }

type Chain<T> = {
  foo<V extends string>(
    name: conform<V, Exclude<V, T>, 'this argument is already used'>,
  ): Chain<T | V>
}

function chain(fn: (s: string) => void): Chain<never> {
  const c = {
    foo(s: string) {
      fn(s);
      return c;
    }
  };
  return c as any;
}

chain(console.log)
.foo('a') // acceptable
.foo('b')
.foo('a')

let cc;
cc = chain(console.log)
cc = cc.foo('a'); // appropriate
cc = cc.foo('b')
cc = cc.foo('a')

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

Arranging React Grid Items with Stylish Overlapping Layout

Is there a way to create a react-grid-layout with 100 grid points width, while ensuring that the grid items do not overlap? https://i.sstatic.net/CQiVh.png (Reducing the number of columns can prevent overlap, but sacrifices the 100-point width resolution ...

Why isn't this working? I'm attempting to trigger a sound when I hover with my cursor, but it only plays when I click instead

When I click on it, it works fine. But I can't seem to get it to work on hover. Can someone help me out? This is the HTML code: <body> <audio autoplay id="HAT2" > <source src="OOOOO_1_HAT.mp3" > Your browser doesn't support t ...

What is the best way to eliminate an object from an array of objects depending on a certain condition?

I have an array of objects structured like so: data = [ { "name":"abc", "email":"<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="fa9b9899ba9d979b9396d4999597">[email protected]&l ...

Struggling with implementing jquery Ajax and a php script to fetch information from a mysql database

I'm encountering issues with my current web app project in displaying a simple jpg image based on the selected radio button using jQuery AJAX along with a PHP script to interact with MySQL. Below is my ajax.js file: $('#selection').change( ...

Updating a particular column in a table with Jquery

In this table : $('#listview-table tr').each(function() { var status_id = $(this).find(".listViewEntryValue").$('[data-name~="cf_1525"]').text(); alert(status_id); }); <table id="listview-table" class="table listv ...

Implementing Othello Minimax Algorithm in React.js Yields Unsuccessful Results

I need assistance with a recurring issue where the AI player consistently plays the first available move it encounters. My objective was to implement an AI using the Minimax Algorithm, but I'm facing challenges in achieving the desired functionality. ...

What is the best way to filter two tables using only one search bar?

In my Vue2 application, I have implemented a pair of data tables on one of the pages. Each table is placed behind a tab, allowing users to choose which one they want to view. The search bar, however, is not confined within a tab as I wanted to avoid duplic ...

Tips for transferring a calculated value from a child component to a parent component in ReactJs

In my current project, I am faced with the challenge of passing a calculated value from a child component back to its parent. The child component is designed to utilize various user inputs to compute a single value that needs to be returned to the parent. ...

Problem with overlapping numbers in the Vis network

I am currently working on a project using Angular 8 and Visnetwork. Everything is going well, but I am facing an issue with overlapping numbers on lines. Is there a way to adjust the position of the numbers on one line without separating the lines? Can s ...

Deciphering JSON data in an Express.js application

In a Node.js/Express.js application, an API call is made to another server which responds with JSON data. However, the received JSON response is not being properly parsed into new variables. What specific modifications should be applied to the code below i ...

Determine the location of an image with the help of Jquery

I'm currently working on finding the position of an image with Jquery. The issue I am facing is that it only provides me with the initial position of the image when the document was loaded. $(".frog").click(function(){ alert($(".frog").position() ...

Simple steps to add a click event listener to every element within a div

I need to assign a click handler to multiple elements and perform different actions based on which one is clicked. To illustrate, I can create an alert displaying the class of the button that was clicked. The elements I am working with have a similar str ...

"Encountering a module not found issue while trying to

Attempting to test out 3 node modules locally by updating their source locations in the package.json files. The modules in question are sdk, ng-widget-lib, and frontend. ng-widget-lib relies on sdk, while frontend depends on ng-widget-lib. To locally build ...

Vue.js isn't triggering the 'created' method as expected

I have a main component called App.vue. Within this component, I have defined the created method in my methods object. However, I am noticing that this method is never being executed. <template> <div id="app"> <Header /> <Ad ...

Endlessly streaming data is requested through HTTP GET requests

I am facing an issue with my code where it requests data endlessly. The service I have retrieves data in the form of an Array of Objects. My intention is to handle all the HTTP requests, mapping, and subscriptions within the service itself. This is because ...

Comparing the map function and for loop in the Puppeteer package for Node.js

I experimented with the Puppeteer package in NodeJS and noticed a significant difference in functionality between using the map function versus a for loop. Here is an illustration of what I observed: Using the map function: data.map(async(info) =>{ ...

Next-auth is in need of a username for the credentials provider

I am currently trying to learn how to implement next-auth in Next.js 13. I have set up a credentials login system with username and password. When I make an API request, I expect to receive a status code of 200 if the credentials are correct. The logic f ...

By default, make the initial element of the list the selected option in an AngularJS select input

I'm running into an issue with setting the first element in my ng-repeat list within a select input. Here is the code snippet causing the problem: <div> <span >OF</span> <select ng-model="eclatementCourante.ordreFabricationId" n ...

Issue encountered while attempting to retrieve data from a local json file due to Cross-Origin Resource Sharing

I'm attempting to fetch and display the contents of a JSON file on a webpage, but I'm encountering this error message: Access to XMLHttpRequest at 'file:///C:/Users/bobal/Documents/htmlTry/myData.json' from origin 'null' has ...

Troubleshooting issues with the add-comment and remove-comment functionalities in a react-redux application

I'm working on a comment widget using react-redux. I've encountered an issue where, when I click on the add comment button, nothing happens. Also, when I try to delete a comment, I get an error saying that map is not a function even though I am p ...