【问题标题】:avoid type casting on promise return避免在承诺返回时进行类型转换
【发布时间】:2021-01-29 11:35:14
【问题描述】:

我有一个使用 API 响应进行一些计算的操作,如下所示

try {
  const data = await FooService.request();

  someCalculation1(data as FooServiceData);
  someCalculation2(data as FooServiceData);
  someCalculation3(data as FooServiceData);
  someCalculation4(data as FooServiceData);
} catch(err) {
  console.log(err)
} 

关键是这很烦人,而且不那么可读,每次都要重新输入as SomeServiceData,但我相信需要这样做,因为我的FooService.request 有这种实现

request(): Promise<SomeServiceData | Error> {
  return callApi()
    .then(res => {
      return res as SomeServiceData;
    })
    .catch(err => {
      console.log(err)
      return Error("Some error")
    })

}

由于函数可以返回每个SomeServiceDataError,它迫使我强制转换类型。但关键是data 永远不会是Error 类型,因为如果是,它不会是,错误将被抛出,err 将是Error 类型。但我不知道如何才能避免这种铸造。

我想把Promise格式的服务改成async/await格式,但我不相信它会改变行为。

【问题讨论】:

    标签: typescript async-await es6-promise typescript-typings


    【解决方案1】:

    一方面,您可以输入data 本身而不是参数表达式:

    const data = (await FooService.request()) as FooServiceData;
    

    但听起来您想在request调用者 中捕获,而不是在request 本身中捕获 - 在request 中省略.catch,以便在出现错误时,调用者将处理它。 (您当前的代码导致data 是一个实际的错误,因为.catch 会产生一个解决返回错误的承诺。)

    试试:

    try {
      const data = await FooService.request();
    
      someCalculation1(data);
      // ...
    } catch(err) {
      console.log(err)
    } 
    
    request() {
      return callApi()
        .then(res => {
          return res as SomeServiceData;
        });
    }
    

    甚至

    request() {
      return callApi() as Promise<SomeServiceData>;
    }
    

    【讨论】:

      【解决方案2】:

      但重点是 data 永远不会是 Error 类型,因为如果是,它不会是,错误将被抛出并且 err 将是 Error 类型。

      这是不正确的。承诺可以在您的实现中解析为Error 对象,因为您在request() 中捕获API 错误并在发生这种情况时返回new Error。当您catch 时,您正在防止错误被抛出。

      您需要检查data 的类型来区分ErrorSomeServiceData,而不是在您的操作中使用try/catch 块。您可以将if ( data instanceof Error ) 用作type guard,并且在两个分支中打字稿知道它只能是那种类型。

        const data = await FooService.request();
      
        if ( data instanceof Error ) {
          // data is Error
          console.log(data.message); 
        } else {
          // data is SomeServiceData
          someCalculation1(data);
        }
      

      或者,如果您想在您的操作中保留try/catch 块,那么您需要更改FooService.request() 以便它抛出错误而不是捕获它。基本上你只需要在两个地方之一捕获错误。一旦被抓住就不会再扔了。

      const FooService = {
        async request(): Promise<SomeServiceData> {
          return await callApi() as SomeServiceData;
        }
      }
      

      现在承诺只能解析为SomeServiceData

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2022-01-22
        • 2016-03-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-28
        • 2019-09-18
        • 1970-01-01
        相关资源
        最近更新 更多