【问题标题】:How to declare a function that throws an error in Typescript如何声明一个在 Typescript 中引发错误的函数
【发布时间】:2018-09-01 06:00:38
【问题描述】:

在 Java 中我会这样声明一个函数:

public boolean Test(boolean test) throws Exception {
  if (test == true)
    return false;
  throw new Exception();
}

而且我可以在不处理异常的情况下使用这个函数。

如果可能的话,如何在 Typescript 中做同样的事情?编译器会告诉我,如果没有 try/catch,我将无法使用该函数。

【问题讨论】:

  • 不,不可能
  • 不确定您是否正在寻找Error 课程,请在下面查看我的答案
  • 您可以通过装饰器对其进行注释以指示该方法可能会抛出,但没有什么可以强制执行。每次调用该方法时,您都必须检查注释。

标签: typescript


【解决方案1】:

TypeScript 中没有这样的功能。仅当函数返回错误而不是抛出错误时才可以指定错误类型(这种情况很少发生并且很容易成为反模式)。

唯一相关的类型是never。仅当函数肯定抛出错误时才适用,不能比这更具体。它和其他任何类型一样,只要不导致类型问题,就不会导致类型错误:

function Test(): never => {
  throw new Error();
}

Test(); // won't cause type error
let test: boolean = Test(); // will cause type error

当函数有可能返回值时,never 被返回类型吸收。

可以在函数签名中指定,但仅供参考:

function Test(test: boolean): boolean | never {
  if (test === true)
    return false;

  throw new Error();
}

它可以向开发人员提示可能出现未处理的错误(以防函数体不清楚),但这不影响类型检查并且不能强制try..catch;这个函数的类型被系统认为是(test: boolean) => boolean

【讨论】:

  • never 被系统省略,以支持返回类型”……这在技术上是不正确的。您不必在返回类型中指定 never 的原因是,在联合中,所有其他类型都吸收它。所以boolean|never 被简化为boolean,就像anything || false 如何简化为anything:在析取中,任何东西吸收 false。在某种程度上,neverunknown 正好相反,unknown 在联合中支配,而在交叉中吸收
  • 感谢您的通知。事实上,吸附在这里是正确的术语。
  • @chharvey 快速说明一下:anything || false 不会简化为 anything(除非您的意思是让 anything 代表所有真实值,但这并不清楚)。如果|| 的左边是假的,JavaScript 会选择右边而不考虑它的值。在你的控制台中尝试null || false,你会看到你得到false
  • @willurd 是的,这是一个小的技术问题,但你是对的。我应该说anything_truthy || false 简化为anything_truthy。感谢您的更正。区别在于anything_truthy || false 是在运行时短路 的表达式,而boolean | never 是静态简化的类型。
  • 很好,感谢never 解决方案,如果我们有一个带有void 的包装错误处理函数,它会消除编译器错误,迫使我们将undefined 添加到返回类型中,它返回未定义由 TS 定义。基本上void vs never.
【解决方案2】:

你至少可以用@throwsjsdoc 来标记函数。即使它在 typescript 编译器中不提供静态分析错误,但如果您尝试忽略抛出的函数,一些好的 IDE 或 linter 可能仍然report a warning...

/** 
 * @throws {Error}
 */
function someFunc() {
    if (Math.random() < 0.5) throw Error();
}
someFunc();

【讨论】:

  • 据您所知,有没有办法在 Visual Studio Code 上启用此类警告?这将非常有帮助。
  • 我检查了 eslint-plugin-jsdoc,但我的理解是 require-throws 规则只强制将异常记录在 JSDoc 中。遗憾的是,它没有在使用该函数的代码中强制执行 try-catch 语句,而这正是我们许多人正在寻找的。有其他选择吗?
【解决方案3】:

目前不可能。您可以查看此请求的功能: https://github.com/microsoft/TypeScript/issues/13219

【讨论】:

    【解决方案4】:

    您可以将 JavaScript 的 Error 视为 Java 的 RuntimeException(未经检查的异常)。 您可以扩展 JavaScript 的 Erroryou have to use Object.setPrototypeOf 以恢复原型链,因为 Error 破坏了它。 this answer 中也解释了对 setPrototypeOf 的需求。

    export class AppError extends Error {
        code: string;
    
        constructor(message?: string, code?: string) {
            super(message);  // 'Error' breaks prototype chain here
            Object.setPrototypeOf(this, new.target.prototype);  // restore prototype chain
            this.name = 'AppError';
            this.code = code;
        }
    }
    
    

    【讨论】:

      【解决方案5】:

      你不能使用纯 ts (vhttps://www.npmjs.com/package/ts-throwable/v/latest

      用法大致如下:

      import { throwable, getTypedError } from 'ts-throwable';
      class CustomError extends Error { /*...*/ }
      
      function brokenMethod(): number & throwable<CustomError> {
          if (Math.random() < 0.5) { return 42 };
          throw new CustomError("Boom!");
      }
      
      try {
          const answer: number = brokenMethod()
      }
      catch(error){
          // `typedError` is now an alias of `error` and typed as `CustomError` 
          const typedError = getTypedError(error, brokenMethod);
      }
      
      

      【讨论】:

      • 仅供参考 throw 不是一个表达式,所以它在三元组中的使用是不正确的
      【解决方案6】:

      不是 TypeScript,但 Hegel 可能会引起兴趣,它是 JavaScript 的另一个类型检查器,并具有此功能。你会写:

      function Test(test: boolean): boolean | $Throws<Exception> {
        if (test)
          return false;
        throw new Exception();
      }
      

      https://hegel.js.org/docs/magic-types#throwserrortype

      【讨论】:

        【解决方案7】:

        这似乎是一个关于这个主题的有趣 PR https://github.com/microsoft/TypeScript/pull/40468

        本公关介绍:

        • 一个新的类型级表达式:throw type_expr。当前抛出类型 仅在实例化时抛出。
        • 一种新的内在类型 TypeToString 打印类型

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-12-16
          • 1970-01-01
          • 1970-01-01
          • 2012-12-31
          • 1970-01-01
          • 1970-01-01
          • 2016-03-13
          相关资源
          最近更新 更多