How can I resolve the TypeScript error 'Function lacks ending return statement and return type does not include 'undefined'' in my code?

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

How can I resolve the TypeScript error 'Function lacks ending return statement and return type does not include 'undefined'' in my code?

问题

以下是代码的翻译部分:

// 以下是您的 TypeScript 代码

const handle = async (): Promise<string> => 'hi';

const make = async (): Promise<string> => {
  const MAX_RETRIES = 2;
  for (let idx = 0; idx <= MAX_RETRIES; idx++) {
    try {
      return await handle();
    } catch (err) {
      if (idx < MAX_RETRIES) {
        continue;
      } else {
        throw err;
      }
    }
  }
};

关于您的问题,TypeScript 报错是因为它无法确定在循环之后是否有返回值。虽然您的理解是 make 函数要么返回一个字符串(在 try 块内),要么在重试次数耗尽后抛出错误,但TypeScript 不知道循环是如何终止的。

为了解决此问题,您可以告诉 TypeScript 在循环后仍然会抛出错误,而不会返回 undefined。您可以使用 throw 语句来明确指定这一点,如下所示:

const make = async (): Promise<string> => {
  const MAX_RETRIES = 2;
  for (let idx = 0; idx <= MAX_RETRIES; idx++) {
    try {
      return await handle();
    } catch (err) {
      if (idx < MAX_RETRIES) {
        continue;
      } else {
        throw err; // 明确告诉 TypeScript 在此处抛出错误
      }
    }
  }
};

这将解决 TypeScript 报错,因为您明确告诉它,循环后要么返回一个字符串,要么抛出一个错误,而不会返回 undefined

英文:

I have the following simple function (make) that calls the handle function and is supposed to retry a number of times whenever that function throws. If the retries are exhausted, the make function should throw the error.

const handle = async (): Promise&lt;string&gt; =&gt; &#39;hi&#39;;

const make = async (): Promise&lt;string&gt; =&gt; {
  const MAX_RETRIES = 2;
  for (let idx = 0; idx &lt;= MAX_RETRIES; idx++) {
    try {
      return await handle();
    } catch (err) {
      if (idx &lt; MAX_RETRIES) {
        continue;
      } else {
        throw err;
      }
    }
  }
};

I'm using TypeScript, which is complaining because the return type doesn't include undefined:
> Function lacks ending return statement and return type does not include 'undefined'.

For reference, this is the TS Playground for the code above.

I'm looking for guidance on how to handle the return type for the function.

Note that:

  • I don't want to change my tsconfigs (currently set to strict)
  • I don't want to modify the return type to Promise&lt;string | undefined&gt;

My understanding is that the make function can only either return a string (inside the try block) or throw an error once the retries have been exhausted. If that's the case then where does the undefined that TS is asking for comes from? Am I missing something?

答案1

得分: 2

我的理解是 make 函数只能在重试次数用尽后要么返回一个字符串(在 try 块内),要么抛出一个错误。

我相当确定你是对的,但是 TypeScript 无法完全跟踪这么复杂的逻辑,因此(我认为是不正确的)它看到函数中有一条路径没有显式的 return,所以隐式地返回 undefined(包装在一个 promise 中)。

你可以通过以下几种方法解决这个问题:

  1. 在末尾添加 return ""; 并附上注释说明它永远不会发生。(不太好。)
  2. 在末尾添加 throw new Error("逻辑错误,永远不会到达这里。");
  3. 重写函数,使最后一次尝试更明显地成为 returnthrow 的情况,方法是使用 < 而不是 <=,然后在末尾重复 return await handle();。(重复它不太好,但非常简单。)

我认为 #2 是最好的选择(或者是 jcalz 的重写),但它们都会让 TypeScript 满意,这实际上是一种风格选择。

英文:

> My understanding is that the make function can only either return a string (inside the try block) or throw an error once the retries have been exhausted.

I'm fairly sure you're right, but TypeScript can't quite follow logic that complex, so it (incorrectly, I think) sees a path through the function that doesn't do an explicit return and so implicitly returns undefined (wrapped in a promise).

You can solve it in a few ways:

  1. Add a return &quot;&quot;; at the end with a comment noting it'll never happen. (Blech.)
  2. Add a throw new Error(&quot;Logic error, this will never be reached.&quot;); at the end.
  3. Rewrite the function to make the final attempt more obviously a return-or-throw situation by using &lt; instead of &lt;= and then repeating the return await handle(); at the end. (Not great to have to repeat it, but it's very simple.)

I don't think #1 or #2 need examples, but here's what #3 might look like:

const make = async (): Promise&lt;string&gt; =&gt; {
    const MAX_RETRIES = 2;
    for (let idx = 0; idx &lt; MAX_RETRIES; idx++) {
        try {
            return await handle();
        } catch (err) {
            continue; // I guess technically we don&#39;t need this, since
                      // the loop doesn&#39;t do anything else
        }
    }
    return await handle();
};

For me, #2 is the winner (or jcalz's rewrite), but any of them will make TypeScript happy, it's really a style choice.

huangapple
  • 本文由 发表于 2023年6月2日 01:35:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/76384387.html
匿名

发表评论

匿名网友

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

确定