typescript 如何在async catch()中使用类型化错误

sz81bmfz  于 2022-11-18  发布在  TypeScript
关注(0)|答案(5)|浏览(281)

我正在使用async函数调用一个现有的基于承诺的API,该API拒绝了带有类型化错误的承诺。
你可以这样嘲笑这种行为:

interface ApiError {
  code: number;
  error: string;
}

function api(): Promise<any> {
  return new Promise((resolve, reject) => {
    reject({ code: 123, error: "Error!" });
  });
}

现在有了promises,我可以将错误类型注解为ApiError

api().catch((error: ApiError) => console.log(error.code, error.message))

但是当使用async时,如果我尝试在try ... catch()中注解错误类型:

async function test() {
  try {
    return await api();
  } catch (error: ApiError) {
    console.log("error", error);
  }
}

编译时出错:
Catch子句变量不能有类型注解。
那么,我怎么知道我期待的是什么样的错误呢?我需要在catch()块中写一个Assert吗?这是async的一个bug/不完整的特性吗?

ruarlubt

ruarlubt1#

在TypeScript中,catch子句变量可能没有类型注解(除了TypeScript 4.0中的unknown)。这并不特定于async。以下是Anders Hejlsberg的解释:
我们不允许在catch子句上使用类型注解,因为我们无法知道异常的类型。您可以抛出任何类型的对象,并且系统生成的异常(如内存不足异常)在技术上随时都可能发生。
您可以检查catch主体中是否存在error.codeerror.message属性(选择性地使用使用者定义的型别保护)。

ax6ht2ek

ax6ht2ek2#

您不能直接将自定义类型分配给错误,但可以使用type guard。type guard是一个函数,它帮助TypeScript的编译器确定错误的类型。
编写一个带有类型 predicate 的类型保护是非常简单的。你只需要实现一个布尔检查,它接受一个值,并判断这个值是否具有你的自定义类型的属性。
对于您的示例,我可以看到您的ApiError有一个名为code的自定义属性,因此类型保护可能如下所示:

function isApiError(x: unknown): x is ApiError {
  if (x && typeof x === 'object' && 'code' in x) {
    return true;
  }
  return false;
}

注意x is ApiError返回类型,这是一个类型 predicate !
使用上面的isApiError函数,TypeScript将有可能检测到您的自定义错误类型:

interface ApiError {
  code: number;
  error: string;
}

function isApiError(x: unknown): x is ApiError {
  if (x && typeof x === 'object' && 'code' in x) {
    return true;
  }
  return false;
}

try {
  return await api();
} catch (error) {
  if (isApiError(error)) {
    // Thanks to the type guard, TypeScript knows know what "error" is
    console.log(error.code);
  }
}

您可以在此处看到类型保护的作用:https://www.youtube.com/watch?v=0GLYiJUBz6k

mccptt67

mccptt673#

此错误与async无关。您不能键入catch变量。
原因很简单:TypeScript中的类型只存在于代码编译之前,一旦编译完成,您得到的就是无类型的JavaScript。
在catch子句上使用类型过滤器需要在运行时检查错误的类型,而且没有可靠的方法来完成这一任务,所以我认为这样的特性不太可能得到支持。

oalqel3c

oalqel3c4#

简单的解决方案

您只需要使用类型Assert来转换错误类型。

catch (err) {
  const error = err as CustomErrorType;
  ...
}
eoxn13cs

eoxn13cs5#

另一个选项是验证错误示例,见下图:

try {
        
} catch (err) {
  if (err instanceof Error) {
    console.log(err.message);
  }
}

相关问题