提问人:marcXandre 提问时间:3/23/2018 最后编辑:JJJmarcXandre 更新时间:3/15/2023 访问量:135656
如何在 Typescript 中声明引发错误的函数
How to declare a function that throws an error in Typescript
问:
在 Java 中,我会声明一个这样的函数:
public boolean Test(boolean test) throws Exception {
if (test == true)
return false;
throw new Exception();
}
我可以在不处理异常的情况下使用此功能。
如果可能,如何在 Typescript 中做同样的事情?编译器会告诉我,如果没有 try/catch,我无法使用该函数。
答:
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
never
anything || false
anything
anything
||
null || false
false
anything_truthy || false
anything_truthy
anything_truthy || false
boolean | never
never
undefined
void
void vs never
目前不可能。您可以查看此请求的功能: https://github.com/microsoft/TypeScript/issues/13219
你不能使用纯 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);
}
评论
throw
您可以将 JavaScript 视为 Java(未选中的异常)。
您可以扩展 JavaScript,但您必须使用 Object.setPrototypeOf
来恢复原型链,因为会破坏它。这个答案中也解释了对 setPrototypeOf 的需求。Error
RuntimeException
Error
Error
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;
}
}
评论
您至少可以用 @throws
jsdoc 标记该函数。即使它没有在打字稿编译器中提供静态分析错误,如果您尝试忽略抛出的函数,一些好的 IDE 或 linter 仍可能会报告警告......
/**
* @throws {Error}
*/
function someFunc() {
if (Math.random() < 0.5) throw Error();
}
someFunc();
评论
不是 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
关于这个话题,这似乎是一个有趣的公关 https://github.com/microsoft/TypeScript/pull/40468
此 PR 介绍:
- 新的类型级表达式:throw type_expr。当前投掷类型 仅在实例化时引发。
- 一种新的内在类型 TypeToString 打印类型
如其他答案所示,在打字稿中,易出错操作的返回类型是 。没有办法将函数标记为抛出,但是您可以使用实用程序类型使其更易于辨别:never
type Result<OK = any> = OK | never;
或者你可以让它更加引人注目:
type Result<OK = any, Error = never> = OK | Error;
同样,这些仅供眼睛使用,无法强制执行 try/catch 块。
如果要强制处理错误,请使用 promise。Linters 可以灌输未经处理的承诺。“typescript-eslint”有“No floating promises”规则。
此外,当存在未处理的 promise 时,某些运行时会发出错误。
来自功能背景,我更喜欢在返回类型中指定预期错误(又名检查异常)。打字稿联合和类型保护使这变得简单:
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和转译器将迫使开发人员处理它们(在大多数情况下)。例如,这将失败:
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
评论
Error
const x = success ? handleX(x) : handleError(err)
handleX
handleError