如何确保一个方法不会两次使用相同的参数调用?

huangapple go评论84阅读模式
英文:

How to make sure a method is not called twice with the same argument?

问题

关于JavaScript(或TypeScript),我试图找到一种方法,确保开发人员不能多次使用相同的参数调用方法。

例如:

const foo = (name: string) => {}
foo("ABC") // 可以
foo("123") // 可以
foo("ABC") // 应该在IDE中显示错误,因为它已经在第一次调用时被调用过

只要清楚,错误应该在“开发”(编译?)时显示。我希望开发人员在编写代码时意识到错误,因此IDE应该触发错误。

我该如何实现它?我应该创建一个tslint错误吗?

请帮忙

编辑:我可能没有百分之百清楚,但如果JavaScript没有允许上述操作的任何特性,那么也可以为我完成任务的是一个新的自定义tslint规则。如果我没有记错,规则可以有一个上下文,它们可以在其中存储一些“缓存”的值。因此,在开发时,我应该能够在IDE中看到错误,就像我们在IDE中看到其他linting规则错误一样。

是否可以实现?我如何创建一个具有执行此任务的上下文的新lint规则?

另外,如果我们执行foo(x),规则无法检测到x的值,顺序也无关紧要,我也不介意。

规则只需要足够智能,能够识别简单的情况即可。

英文:

Talking about JavaScript (or typescript), I'm trying to find a way to make sure that developers can't call a method multiple times with the same argument.

For example:

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


foo("ABC") // ok

foo ("123") // ok

foo ("ABC") // should show an error in the IDE, as it was already called in the first interaction

Just to be clear, the error should be shown at "developing" (compilation?) time. I want developers to be aware of the mistake while coding, so the IDE should trigger the error.

How can I achieve it? Should I create a tslint error?
Please help

Edit: I may have not been 100% clear, but if no feature of JavaScript allows the above, then what also will do the job for me is probably a new custom tslint rule. If I'm not mistaken, rules can have a context where they can store some "cached" values. Hence, at development time, I should be able to see an error the same way we see other linting rules error in the IDE.

Can it be achieved? How can I create a new lint rules with a context that does the job?

Also, I don't mind if we do foo(x) and the rule is not able to detect what value x is, and I don't mind the order on which the function is called.

The rule has to be just smart enough to reckon simple cases where it can.

答案1

得分: 2

I don't think you can statically do that, but you can throw an error at runtime in development only:

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)
  }

  ...
}

The whole if (process.env.NODE_ENV === 'development') { ... } block won't be present in non-development builds.

英文:

I don't think you can statically do that, but you can throw an error at runtime in development only:

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)
  }

  ...
}

The whole if (process.env.NODE_ENV === 'development') { ... } block won't be present in non-development builds.

答案2

得分: 1

很抱歉,TypeScript或JavaScript没有内置此类功能。据我所知,在JavaScript或TypeScript中,没有机制允许您根据运行时值或使用情况在编译时强制执行限制。这些语言简单地没有设计来跟踪这种使用情况。

通常,像TypeScript这样的静态类型检查器基于静态分析来检查类型,不涉及执行或跟踪代码。因此,TypeScript无法提供依赖于代码的运行时行为的检查,比如函数调用的顺序或频率。

要及早捕获这些逻辑问题,通常更好的方法是单元测试。您可以编写一个测试,断言foo在使用相同的参数调用两次时会引发错误,然后在开发过程中经常运行您的测试。或者,您可以考虑使用支持自定义规则的linter或静态分析工具,但我认为目前没有任何现有工具可以处理这种特殊情况。

如果您想强制执行这样的规则,最好的选择可能是提供文档或注释来解释要求,并依赖开发人员手动遵守要求。

还有可能您的用例可以通过不同的模式或结构更好地满足。如果您发现自己需要阻止开发人员多次使用相同的参数调用方法,也许值得考虑一种在第一次就不允许这种可能性的设计。

英文:

Unfortunately, TypeScript or JavaScript doesn't have this kind of feature built-in. As far as I know, there's no mechanism within JavaScript or TypeScript that allows you to enforce a restriction at compile-time based on runtime values or usage. The languages simply aren't designed to keep track of this kind of usage.

Typically, a static type checker like TypeScript checks types based on static analysis, which doesn't involve executing or tracing the code. As a result, TypeScript can't provide checks that depend on the runtime behaviour of the code, like the order or frequency of function calls.

For catching these types of logical issues early, unit tests are often a better approach. You could write a test that asserts foo throws an error when called with the same argument twice, and then run your tests often during development. Alternatively, you could look into using a linter or static analysis tool that supports custom rules, but I don't think any existing tool can handle this specific case.

If you want to enforce a rule like this, your best bet might be to provide documentation or comments explaining the requirement, and to rely on developers to manually adhere to the requirement.

It's also possible that your use case could be better served with a different pattern or structure. If you find yourself needing to prevent developers from calling a method multiple times with the same argument, it might be worth considering a design that doesn't allow for that possibility in the first place

答案3

得分: 0

使用链式调用来列出已使用的参数
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') // ok
  .foo('b') // ok
  .foo('a') // Argument of type 'string' is not assignable to parameter
  //   ~~~     of type '{ error: "this argument is already used"; }'.(2345)

let cc;
cc = chain(console.log)
cc = cc.foo('a'); // ok
cc = cc.foo('b'); // ok
cc = cc.foo('a'); // Argument of type 'string' is not assignable to parameter
//          ~~~     of type '{ error: "this argument is already used"; }'.(2345)
英文:

You may use chaining to list used arguments
https://tsplay.dev/WJpZrN

type conform&lt;T, V, E&gt; = T extends V ? T : { error: E }

type Chain&lt;T&gt; = {
  foo&lt;V extends string&gt;(
    name: conform&lt;V, Exclude&lt;V, T&gt;, &#39;this argument is already used&#39;&gt;,
  ): Chain&lt;T | V&gt;
}

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

chain(console.log)
.foo(&#39;a&#39;) // ok
.foo(&#39;b&#39;) // ok
.foo(&#39;a&#39;) // Argument of type &#39;string&#39; is not assignable to parameter
//   ~~~     of type &#39;{ error: &quot;this argument is already used&quot;; }&#39;.(2345)

let cc;
cc = chain(console.log)
cc = cc.foo(&#39;a&#39;); // ok
cc = cc.foo(&#39;b&#39;); // ok
cc = cc.foo(&#39;a&#39;); // Argument of type &#39;string&#39; is not assignable to parameter
//          ~~~     of type &#39;{ error: &quot;this argument is already used&quot;; }&#39;.(2345)

答案4

得分: -3

为了确保开发者不能多次使用相同的参数调用方法,您可以创建一个缓存机制来跟踪已经传递给函数的参数。在JavaScript中实现这一目标的一种方法是使用闭包来存储缓存并检查重复参数。

const createUniqueFunction = () => {
  const cache = new Set();

  const foo = (name) => {
    if (cache.has(name)) {
      console.error(`错误:"${name}" 已经被用作参数。`);
      return;
    }

    // 在这里执行与参数相关的操作
    console.log(`处理参数:"${name}"`);

    // 将参数添加到缓存中
    cache.add(name);
  };

  return foo;
};

// 使用示例:
const foo = createUniqueFunction();

foo("ABC"); // 可行
foo("123"); // 可行
foo("ABC"); // 错误:"ABC" 已经被用作参数。

在这个示例中,我们使用闭包创建了 createUniqueFunction 函数,它返回 foo 函数。闭包内部的 cache 变量是一个存储传递给 foo 的参数的 Set。在处理参数之前,我们检查它是否已经存在于缓存中。如果是,我们会记录错误消息并提前返回,不执行操作。

通过使用这种方法,多次使用相同参数调用 foo 将导致错误消息,防止重复使用相同参数进行调用。

请记住,上述代码只在使用 createUniqueFunction 创建 foo 函数时才有效。如果单独创建另一个 foo 函数,它将拥有自己独立的缓存。如果需要确保在多个实例之间的唯一性,可以探索其他方法,比如使用全局缓存或自定义数据结构。

英文:

To ensure that developers can't call a method multiple times with the same argument, you can create a caching mechanism to keep track of the arguments that have already been passed to the function. One approach to achieve this in JavaScript is by using a closure to store the cache and check for duplicate arguments.

const createUniqueFunction = () =&gt; {
const cache = new Set();
const foo = (name) =&gt; {
if (cache.has(name)) {
console.error(`Error: &quot;${name}&quot; has already been used as an argument.`);
return;
}
// Do whatever you want to do with the argument here
console.log(`Processing argument: &quot;${name}&quot;`);
// Add the argument to the cache
cache.add(name);
};
return foo;
};
// Usage example:
const foo = createUniqueFunction();
foo(&quot;ABC&quot;); // ok
foo(&quot;123&quot;); // ok
foo(&quot;ABC&quot;); // Error: &quot;ABC&quot; has already been used as an argument.

In this example, we use a closure to create the createUniqueFunction function, which returns the foo function. The cache variable inside the closure is a Set that stores the arguments passed to foo. Before processing the argument, we check if it already exists in the cache. If it does, we log an error message and return early without performing the operation.

By using this approach, calling foo multiple times with the same argument will result in an error message, preventing duplicate calls with the same argument.

Keep in mind that the above code will work as long as the foo function is created using createUniqueFunction. If you create another foo function separately, it will have its own independent cache. If you need to ensure uniqueness across multiple instances, you could explore other approaches like using a global cache or a custom data structure.

huangapple
  • 本文由 发表于 2023年8月4日 00:45:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/76830099.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定