catch 内的错误对象的类型未知

Mat*_*ann 95 try-catch typescript

我有以下代码:

try {
  phpDoc(vscode.window.activeTextEditor);
} catch (err) {
  console.error(err);
  vscode.window.showErrorMessage(err.message);
}
Run Code Online (Sandbox Code Playgroud)

但是在 上err.message出现错误,但我无法在 中键入对象。Object is of type 'unknown'.ts(2571)err.catch (err: Error)

我应该怎么办?

Ole*_*ter 94

作为对certainPerformance的补充答案:

在 TypeScript 4.0 之前,catch子句绑定被设置为允许any轻松访问属性message。这是不安全的,因为不能保证抛出的内容将从Error原型继承 - 只是作为最佳实践,我们不会抛出除错误之外的任何内容

(() => {
    try {
        const myErr = { code: 42, reason: "the answer" };
        throw myErr; //don't do that in real life
    } catch(err) {
        console.log(err.message); //undefined
    }
})();
Run Code Online (Sandbox Code Playgroud)

TypeScript 4.0引入了更安全子句的选项catch,允许您将参数注释为unknown,强制您执行显式类型断言,或者更好的是进行类型保护(这使得该子句既是编译时安全的,也是运行时安全的)。

但是,为了避免破坏大多数代码库,您必须明确选择新行为:

(() => {
    try {
        throw new Error("ouch!");
    } catch(err: unknown) {
        console.log(err.message); //Object is of type 'unknown'
    }
})();
Run Code Online (Sandbox Code Playgroud)

TypeScript 4.4 引入了一个新的编译器选项,useUnknownInCatchVariables该选项强制执行此行为。false默认情况下是这样,但如果您strict打开了该选项(您应该这样做),它就会打开,这很可能是您首先收到错误的原因。

  • @theProCoder 好吧,这是解决这个问题的一种方法。剩下的取决于你对严格类型检查的虔诚程度:当然,最安全的方法是使用“instanceof”实际执行运行时检查(兼作守卫)(参见 certainPerformance 的答案),这是没有运行时负担的最“诚实”的方法是一个类型断言(因为我们实际上只是“假设”“catch”块参数是某种类型),而最“请走开”的方法是,明确地将“useUnknownInCatchVariables”设置为 false(参见 dast 的回答) (7认同)
  • 那么,要修复它,您是否再次将 `useUnknownInCatchVariables` 设置为 false? (3认同)

小智 63

如果您不想在升级 TypeScript 后更改所有代码,但处于严格模式,则可以在strict覆盖它的选项之后添加以下编译器选项,如Oleg 的答案中所暗示的:

tsconfig.json

{
  "compilerOptions": {
    [...]
    "strict": true,
    "useUnknownInCatchVariables": false,
    [...]
    },
  },
}
Run Code Online (Sandbox Code Playgroud)

"strict": true,设置useUnknownInCatchVariables为 true,然后"useUnknownInCatchVariables": false,覆盖它并将其设置回 false。

  • TSconfig.json 文件中允许注释,请参阅 https://github.com/microsoft/TypeScript/issues/4987 (3认同)
  • @鲍里斯不知道这与实际答案有什么关系,当它明确用于示例时。 (2认同)

Cer*_*nce 53

因为任何东西都可以扔,所以unknown

const fn = () => {
  throw 'foo';
};
try {
  fn();
} catch(e) {
  console.log(e);
  console.log(e instanceof Error);
  console.log(e === 'foo');
}
Run Code Online (Sandbox Code Playgroud)

在访问该属性之前,您需要检查是否err确实存在错误以缩小范围message

try {
  phpDoc(vscode.window.activeTextEditor);
} catch (err) {
  console.error(err);
  if (err instanceof Error) {
    vscode.window.showErrorMessage(err.message);
  } else {
    // do something else with what was thrown, maybe?
    // vscode.window.showErrorMessage(String(err));
  }
}
Run Code Online (Sandbox Code Playgroud)


nei*_*eil 6

您不能在打字稿中为 catch 子句变量编写特定的注释,这是因为在 javascript 中,catch 子句将捕获引发的任何异常,而不仅仅是指定类型的异常。

在打字稿中,如果您只想捕获特定类型的异常,则必须捕获抛出的任何内容,检查它是否是您想要处理的异常类型,如果不是,则再次抛出它。

含义:在执行任何操作之前,请先确保引发的错误是 axios 错误。

解决方案1

使用类型断言
使用 AxiosError 来转换错误

import  { AxiosError } from 'axios';

try {
    // do some api fetch
    } catch (error) {
    const err = error as AxiosError
    // console.log(err.response?.data)
    if (!err?.response) {
        console.log("No Server Response");
    } else if (err.response?.status === 400) {
        console.log("Missing Username or Password");
    } else {
        console.log("Login Failed");
    }  
}
Run Code Online (Sandbox Code Playgroud)
解决方案2

在执行任何操作之前,请先检查错误是否为 axios 错误

import axios from "axios"

try {
    // do something
} catch (err) {
    // check if the error is an axios error
    if (axios.isAxiosError(err)) {
        // console.log(err.response?.data)
        if (!err?.response) {
            console.log("No Server Response");
        } else if (err.response?.status === 400) {
            console.log("Missing Username or Password");
        } else {
            console.log("Login Failed");
        } 
    } 
}
Run Code Online (Sandbox Code Playgroud)