为什么Catch子句变量类型注释必须是any?

raf*_*adu 96 typescript

我正在使用 yup 来验证表单,并且在尝试使此 catch 工作时遇到了此类型错误:

第 1196 章

我的代码:

const handleSubmit = async (): Promise<void> => {
    try {
      const isValid = await userSchema.validate(values, { abortEarly: false });
      console.log(isValid);
    } catch (err: ValidationError) {
      console.log(err);
      const errors = getValidationErrors(err);
    }
Run Code Online (Sandbox Code Playgroud)

getValidationErrors 函数:

export function getValidationErrors(err: yup.ValidationError): Errors {
  console.error(err);
  const validationErrors: Errors = {};
  err.inner.forEach((error) => {
    if (error.path) validationErrors[error.path] = error.message;
  });
  return validationErrors;
}
Run Code Online (Sandbox Code Playgroud)

在搜索它时,我发现 Typescript 不接受子句 catch 参数的类型......这是为什么?这在 Java 或其他语言中很常见...我的意思是...我的解决方案是 attribute err: any...但是 type any 不是永远不会使用的东西吗?

Nic*_*wer 124

Typescript 不允许您这样做,因为 Typescript 无法在编译时验证代码唯一可以抛出的问题是 ValidationError。就此而言,您也不知道:如果由于超出了最大调用堆栈而收到 RangeError 该怎么办?显然这是不可能的(在调用它之前你必须建立一个大的调用堆栈),但是这段代码不能保证它不会发生。

如果您希望错误具有某种类型,则需要添加代码来验证它实际上是该类型:

catch (err: unknown) {
  if (err instanceof ValidationError) {
     // Inside this block, err is known to be a ValidationError
  }
}
Run Code Online (Sandbox Code Playgroud)

或者你需要使用类型断言来告诉打字稿“我知道它是这种类型,相信我”:

catch (err: unknown) {
  getValidationErrors(err as ValidationError);
}
Run Code Online (Sandbox Code Playgroud)
// or:
catch (err: unknown) {
  const knownError = err as ValidationError;
  getValidationERrors(knownError);
}
Run Code Online (Sandbox Code Playgroud)

这在 Java 或其他语言中很常见......

不同的语言对其设计有不同的限制。例如,在 Java 中,您可以定义函数将抛出哪些错误作为函数定义的一部分,如

public static FileInputStream example(String fileName) throws FileNotFoundException {
Run Code Online (Sandbox Code Playgroud)

javascript 和 typescript 都无法在函数定义中指定这一点。

java 允许你有多个 catch 块,不同类型的错误由不同的错误处理,但由于 typescript 仅在编译时存在,所以这不是一个选项。一切都必须在单个 catch 块中处理,并且必须使用显式代码来区分正在处理的错误类型。


kay*_*ya3 15

您无法在 Typescript 中为子句变量编写特定的注释catch,因为在 Javascript 中,catch子句将捕获引发的任何异常,而不仅仅是指定类型的异常。

Java 允许你(实际上,要求你)编写异常的类型,因为在编译时它能够检查(对于已检查的异常类型)是否可以抛出该异常,但更重要的是,在运行时它会检查什么类型抛出异常,并且仅catch当异常类型与catch子句匹配时才捕获它(执行块)。

在 Typescript 中,如果你只想捕获特定类型的异常,则必须捕获抛出的任何异常,检查它是否是你想要处理的异常类型,如果不是,则再次抛出:

try {
    // code that could throw ValidationError
} catch(e: unknown) {
    if(!(e instanceof ValidationError)) { throw e; }
    // code to handle ValidationError
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,在if语句之后,e的类型将缩小为ValidationError并且您可以访问e.message.


小智 11

正如其他人所指出的,TS 不允许您在 catch 子句中使用“any”或“unknown”以外的类型。

但是,您可以将错误变量转换为特定类型。使用 myVariable.

try {
  // where some ValidationError object could be thrown
} catch (err: unknown) {
   const errors = getValidationErrors(<ValidationError>err);
}
Run Code Online (Sandbox Code Playgroud)


Ant*_*nes 5

根据这篇Typescript 文档,在 TS 4.0 版本之前,catch 子句参数通常键入为any,并且在处理第一个参数时可能会导致新的错误。

例子:

try {
  // Do something
} catch (x) {
  console.log(x.message);
}
Run Code Online (Sandbox Code Playgroud)

如果没有message房产怎么办x是的,现在你有一个新的错误

unknowntype 作为 的安全替代方案而存在any,因为类型操作unknown是非法的,因此您必须unknown在执行任何操作之前对变量进行类型检查。

另外根据文档,类型any

缺乏任何类型安全,可能会因无效操作而出错。

因此我们可以得出结论,您应该继续避免使用any.

希望我的回答对你有帮助。