我了解ts中不进行类型安全错误处理的原因是因为我们缺少函数中的throws
子句。因此,每当我这样做时,都会这样:
function mighThrow(input: number): void {
if (input === 1) {
throw new TypeError('cannot be one')
} else if(input === 2) {
throw new SyntaxError('invalid syntax: 2')
}
console.log('all good', input)
}
我无法准确输入错误:
try {
mighThrow(1)
} catch(e) {
// e is any, even though it could be TypeError | SyntaxError
}
问题与Promise
相同,catcher functions参数是硬编码的any
:
interface Promise<T> {
then<TResult1 = T, TResult2 = never>(onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Promise<TResult1 | TResult2>;
catch<TResult = never>(onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): Promise<T | TResult>;
}
catch
的论点是任意的。
我的问题是我该如何解决?如果我是图书馆作者,有没有一种类型安全的方法来帮助用户弄清楚他们在捕捉什么?我知道一些解决方案,例如添加Either
类型并每天调用它,但这会强制现场处理错误,这只会使代码变成类似于该语言将检查异常的方式。 / p>
答案 0 :(得分:2)
由于当前有no throws
in TypeScript,因此任何建议都将看起来是一种解决方法。您正在寻找一种解决方案,该方案不会给想要忽略错误的用户带来任何开销,但可以使想要捕获错误的用户获得更强的错误类型。
这样的事情怎么样(需要TS3.1才能正常工作):
function mighThrow(input: number): void {
if (input === 1) {
throw new TypeError('cannot be one')
} else if (input === 2) {
throw new SyntaxError('invalid syntax: 2')
}
console.log('all good', input);
}
mighThrow.throws = undefined! as TypeError | SyntaxError;
在这里,我们使用了function property declaration来声明一个名为throws
的幻像属性。幻像属性是在运行时实际上并不存在的属性,但是编译器认为确实存在,因此编译器会维护额外的类型信息。在这种情况下,undefined! as TypeError | SyntaxError
在运行时只是undefined
,但是编译器认为mighThrow
具有类型throws
的{{1}}属性。
现在,当人们想捕获错误时,他们可以使用帮助器功能:
TypeError | SyntaxError
像这样:
type ThrowsType<T> = T extends { throws: infer E } ? E : unknown;
const asTypedError = <FS extends Function[]>(e: any, ...f: FS): ThrowsType<FS[number]> => e;
这绝对不是完美的。它要求错误捕获器跟踪自己调用了哪些函数。包含多个功能的try-catch块需要将所有这些功能传递给try {
const x = mighThrow(123);
} catch (err) {
const typedErr = asTypedError(mighThrow, err);
// typedErr is now TypeError | SyntaxError
if (typedErr instanceof TypeError) {
typedErr; // TypeError
} else {
typedErr; // SyntaxError
}
}
:
asTypedError()
实际上,没有任何保证形式来说明所捕获的错误是在declare const alsoMightThrow: { throws: URIError } & ((input: string) => number);
try {
const x = mighThrow(alsoMightThrow("hey"));
} catch (err) {
const typedErr = asTypedError(err, mighThrow, alsoMightThrow); //
// typedErr: TypeError | SyntaxError | URIError
}
属性中声明的类型……这取决于库维护者是否正确(很难,因为有很多东西会在运行时抛出throws
。相反,大多数函数将没有这样的TypeError
属性,因此对于普通开发人员来说,使用这种类型的错误捕获没有太多动机。如果有人在其中放置非throws
函数,则throws
将输出unknown
错误,几乎没有asTypedError
有用。您必须教育图书馆用户如何使用此功能,此时,仅使功能document变得更容易,并且错误捕获程序可以执行自己的any
检查以缩小范围instanceof
。这是缺少语言功能的一种解决方法,看起来像它。 ♀️
哦,希望能有所帮助。祝你好运!