如何使用TypeScript Map和错误处理程序?

gas*_*ard 7 typescript

为什么TypeScript会抱怨这段代码?

class FooError extends Error {
}

const map = new Map<ErrorConstructor, any> ([
  [Error, 'do this'],
  [FooError, 'do that']
])
Run Code Online (Sandbox Code Playgroud)

类型'typeof FooError'不能分配给'ErrorConstructor'类型.

jca*_*alz 4

好吧,让我们看看 的定义ErrorConstructor

interface ErrorConstructor {
    new(message?: string): Error; // is a constructor
    (message?: string): Error; // is callable
    readonly prototype: Error; // has an Error prototype
}
Run Code Online (Sandbox Code Playgroud)

因此, anErrorConstructor需要是一个带有可选字符串参数的构造函数,它还需要可作为函数调用,并且需要有一个Error原型。让我们看看你的FooError班级:

class FooError extends Error {
}
FooError.prototype; // okay, type FooError
new FooError("okay"); // okay
FooError("oops"); // error
Run Code Online (Sandbox Code Playgroud)

它有一个FooError原型,这很好,因为FooError它是 的子类型Error。它是一个构造函数,并且它接受一个参数,因为它遵循超类Error,即一个ErrorConstructor. 但它不能作为函数调用。所以FooError不是一个ErrorConstructor.


此时,您需要决定您是否真的关心它是一个ErrorConstructor. 您打算将其称为 asFooError('msg')而不是 吗new FooError('msg')?我对此表示怀疑。就此而言,您关心构造函数的prototype类型吗FooError?可能不会。在这种情况下,不要使用ErrorConstructor. 相反,使用以下接口,它只关心是否是一个可选的单字符串参数构造函数:

interface NoFrillsErrorConstructor {
  new(message?: string): Error;
}
Run Code Online (Sandbox Code Playgroud)

现在你的代码可以工作了:

const map = new Map<NoFrillsErrorConstructor, any> ([
  [Error, 'do this'],
  [FooError, 'do that']
])
Run Code Online (Sandbox Code Playgroud)

只要您只使用映射的键作为构造函数,一切都会好起来的:

map.forEach((val, err) => {
  err.prototype; // exists, but is type any.  Who cares, right?
  new err(); // okay
  err(); // not okay
})
Run Code Online (Sandbox Code Playgroud)

(如果您确实关心FooError遵守ErrorConstructor,可以安排,但这有点烦人。如果您希望我详细说明,请告诉我。)

无论如何,希望有帮助;祝你好运!