如何在Typescript中声明抛出错误的函数

kqhtkvqz  于 2023-03-19  发布在  TypeScript
关注(0)|答案(9)|浏览(242)

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

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

而且我可以在不处理异常的情况下使用这个函数。
如果可能的话,如何在Typescript中做同样的事情?编译器会告诉我,如果没有try/catch,我就不能使用这个函数。

0x6upsns

0x6upsns1#

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;键入system时,此函数的类型被视为(test: boolean) => boolean

zour9fqk

zour9fqk2#

你至少可以用@throws jsdoc来标记函数,即使它在typescript编译器中不提供静态分析错误,一些好的IDE或linter仍然可能报告警告,如果你试图忽略抛出...

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

xa9qqrwz

xa9qqrwz3#

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

hmae6n7t

hmae6n7t4#

你可以把JavaScript的Error当作Java的RuntimeException(未检查的异常)。你可以扩展JavaScript的Error,但是你必须使用Object.setPrototypeOf来恢复原型链,因为Error破坏了它。setPrototypeOf的必要性也在this answer中解释过。

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;
    }
}
14ifxucb

14ifxucb5#

你不能使用pure ts(v〈3.9)我希望它在将来可以使用。但是有一个解决方法是可能的,它包括隐藏方法签名中可能抛出的类型,然后在catch块中恢复这些类型。我在这里用这个解决方法做了一个包:https://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);
}
2ledvvac

2ledvvac6#

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

  • 新的类型级表达式:throw type_expr。当前throw类型仅在示例化时引发。
  • 打印类型的新内部类型TypeToString
tyu7yeag

tyu7yeag7#

由于我有函数背景,所以我更喜欢在返回类型中指定预期错误(也就是检查异常),类型脚本联合和类型保护使这变得简单:

class ValidationError {
  constructor(readonly message: string) {}

  static isInstance(err: unknown): err is ValidationError {
    if (err === undefined) return false
    if (typeof err !== 'object') return false
    if (err === null) return false
    return err instanceof ValidationError
  }
}

function toInt(num: string): number | ValidationError {
  const result = Number.parseInt(num)
  if (result === undefined) return new ValidationError(`Invalid integer ${num}`)
  return result
}

// caller
const result = toInt("a")
if (ValidationError.isInstance(result))
  console.log(result.message)
else
  console.log(`Success ${result}`)

通过这种方式,函数签名可以向其他开发人员强调潜在的错误。更重要的是,IDE和transpiler将强制开发人员处理这些错误(在大多数情况下)。例如,这将失败:

const result = toInt("a")
const doubled = result * 2

error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number', 'bigint' or an enum type
jtw3ybtb

jtw3ybtb8#

正如其他答案所指出的,在typescript中,一个易出错操作的返回类型是never。没有办法将一个函数标记为抛出,但是你可以使用一个实用程序类型来使它更容易识别:

type Result<OK = any> = OK | never;

或者你可以让它更引人注目:

type Result<OK = any, Error = never> = OK | Error;

同样,这些都是为了眼睛,没有办法强制尝试/捕捉块。
如果你想强制处理错误,使用promise。Linter可以捕获未处理的promise。“typescript-eslint”有“无浮动promise”规则。
https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/eslint-plugin/docs/rules/no-floating-promises.md
还有一些运行时在存在未处理的承诺时发出错误。

2jcobegt

2jcobegt9#

不是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

相关问题