使用 Closure Compiler 时的扩展错误
Extending Error when using Closure Compiler
我正在使用 Closure 编译器并尝试对错误 'class' 进行子类化。我有一个试图做到这一点的元函数。它看起来像这样:
/**
* @param {string} name
* @param {(function(new:Error)?)=} parent
* @param {(Function?)=} constructor
* @return {function(new:Error)}
* @usage
* var MyError = subclassError('MyError', null, function (x, y) {
* this.message = prop1 + " " + prop2;
* });
* throw new MyError(new Error(), 1, 2);
**/
function subclassError (name, parent, constructor) {
// allow subclassing of other errors
if (!parent) parent = Error;
// allow no constructor to be provided
if (!constructor) {
/** @this {Error} */
constructor = function (msg) { if (msg) this.message = msg; };
}
/**
* @constructor
* @extends {Error}
* @param {Error} error
* @param {...*} var_args
**/
var func = function (error, var_args) {
// this check is just a guard against further errors
// note that we don't use something like getOwnPropertyNames
// as this won't work in older IE
var propsToCopy = ['fileName', 'lineNumber', 'columnNumber',
'stack', 'description', 'number', 'message'];
for (var i = 0; i < propsToCopy.length; i++) {
this[propsToCopy[i]] = error[propsToCopy[i]];
}
this.name = name;
constructor.apply(this, Array.prototype.slice.call(arguments, 1));
};
func.prototype = Object.create(parent.prototype);
func.prototype.constructor = func;
func.name = constructor.name;
return func;
}
基本上,上述函数创建了 Error 的子类,调用时需要传入原生 Error
对象。它从这个对象中填充行号、堆栈跟踪等内容。但它也允许您传递其他参数。
这是一个使用示例:
/**
* @constructor
* @extends {Error}
* @param {Error} err
* @param {number} bar
* @param {number} baz
**/
var FooError = subclassError('FooError', null, function (bar, baz) {
this.message = "invalid bar: '" + bar + "', (using '" + baz + "')";
});
/**
* Frobs the noid.
* @param {number} x
* @param {number} y
* @throws FooError
**/
function frob (x, y) {
if (x < 0) throw new FooError(new Error(), x, y);
}
当我像这样用 Closure 编译它时:
java -jar compiler.jar
--compilation_level ADVANCED_OPTIMIZATIONS --warning_level VERBOSE
--language_in ECMASCRIPT5 --language_out ECMASCRIPT3
--js_output_file=frob.min.js frob.js
我收到以下警告:
frob.js:39: WARNING - inconsistent return type
found : function (new:func, (Error|null), ...*): undefined
required: function (new:Error): ?
return func;
^
frob.js:60: WARNING - Function FooError: called with 3
argument(s). Function requires at least 0 argument(s) and no more
than 0 argument(s).
if (x < 0) throw new FooError(new Error(), x, y);
这里有一个棘手的事情是,虽然我知道(从代码中)func
对象是从 Error
派生出来的,因为 Error
的后代是传入的 或 我们使用 Error
作为父级,Closure 认为它是 func
的实例而不是 Error
的实例。我尝试在上面添加一个 @extends {Error}
来纠正问题,但 Closure 仍然认为 !(func instanceof Error)
。这是第一次警告。
在第二个警告中,问题在于它无法识别 FooError
接受三个参数。我尝试将三个参数添加到 FooError
,但由于 Closure 没有看到参数列表,因此无法找到它。
有没有办法通过告诉 Closure 更多信息来消除这些警告?或者有没有一种方法可以更简单地扩展 Closure 中的 Error
,让我们可以获取行号、堆栈等?
因为您正在调用一个 return 构造函数的方法,所以我们必须有点技巧才能在编译器中进行完整的类型检查。
首先,将subclassError
方法改为return未知类型,这样我们就可以独立定义类型签名了:
/**
* @param {string} name
* @param {(function(new:Error)?)=} parent
* @param {(Function?)=} constructor
* @return {?}
**/
function subclassError (name, parent, constructor) {}
接下来,我们为FooError
添加一个存根定义,以便编译器能够理解类型信息。然后我们实际给subclassError
方法的结果赋值
/**
* @constructor
* @extends {Error}
* @param {Error} err
* @param {number} bar
* @param {number} baz
**/
var FooError = function(err, bar, baz) {};
FooError = subclassError('FooError', null, function (bar, baz) {
this.message = "invalid bar: '" + bar + "', (using '" + baz + "')";
});
现在我们从编译器得到正确的类型检查
// The compiler will warn that FooError is called with
// the wrong number of arguments
new FooError(new Error());
我正在使用 Closure 编译器并尝试对错误 'class' 进行子类化。我有一个试图做到这一点的元函数。它看起来像这样:
/**
* @param {string} name
* @param {(function(new:Error)?)=} parent
* @param {(Function?)=} constructor
* @return {function(new:Error)}
* @usage
* var MyError = subclassError('MyError', null, function (x, y) {
* this.message = prop1 + " " + prop2;
* });
* throw new MyError(new Error(), 1, 2);
**/
function subclassError (name, parent, constructor) {
// allow subclassing of other errors
if (!parent) parent = Error;
// allow no constructor to be provided
if (!constructor) {
/** @this {Error} */
constructor = function (msg) { if (msg) this.message = msg; };
}
/**
* @constructor
* @extends {Error}
* @param {Error} error
* @param {...*} var_args
**/
var func = function (error, var_args) {
// this check is just a guard against further errors
// note that we don't use something like getOwnPropertyNames
// as this won't work in older IE
var propsToCopy = ['fileName', 'lineNumber', 'columnNumber',
'stack', 'description', 'number', 'message'];
for (var i = 0; i < propsToCopy.length; i++) {
this[propsToCopy[i]] = error[propsToCopy[i]];
}
this.name = name;
constructor.apply(this, Array.prototype.slice.call(arguments, 1));
};
func.prototype = Object.create(parent.prototype);
func.prototype.constructor = func;
func.name = constructor.name;
return func;
}
基本上,上述函数创建了 Error 的子类,调用时需要传入原生 Error
对象。它从这个对象中填充行号、堆栈跟踪等内容。但它也允许您传递其他参数。
这是一个使用示例:
/**
* @constructor
* @extends {Error}
* @param {Error} err
* @param {number} bar
* @param {number} baz
**/
var FooError = subclassError('FooError', null, function (bar, baz) {
this.message = "invalid bar: '" + bar + "', (using '" + baz + "')";
});
/**
* Frobs the noid.
* @param {number} x
* @param {number} y
* @throws FooError
**/
function frob (x, y) {
if (x < 0) throw new FooError(new Error(), x, y);
}
当我像这样用 Closure 编译它时:
java -jar compiler.jar
--compilation_level ADVANCED_OPTIMIZATIONS --warning_level VERBOSE
--language_in ECMASCRIPT5 --language_out ECMASCRIPT3
--js_output_file=frob.min.js frob.js
我收到以下警告:
frob.js:39: WARNING - inconsistent return type
found : function (new:func, (Error|null), ...*): undefined
required: function (new:Error): ?
return func;
^
frob.js:60: WARNING - Function FooError: called with 3
argument(s). Function requires at least 0 argument(s) and no more
than 0 argument(s).
if (x < 0) throw new FooError(new Error(), x, y);
这里有一个棘手的事情是,虽然我知道(从代码中)func
对象是从 Error
派生出来的,因为 Error
的后代是传入的 或 我们使用 Error
作为父级,Closure 认为它是 func
的实例而不是 Error
的实例。我尝试在上面添加一个 @extends {Error}
来纠正问题,但 Closure 仍然认为 !(func instanceof Error)
。这是第一次警告。
在第二个警告中,问题在于它无法识别 FooError
接受三个参数。我尝试将三个参数添加到 FooError
,但由于 Closure 没有看到参数列表,因此无法找到它。
有没有办法通过告诉 Closure 更多信息来消除这些警告?或者有没有一种方法可以更简单地扩展 Closure 中的 Error
,让我们可以获取行号、堆栈等?
因为您正在调用一个 return 构造函数的方法,所以我们必须有点技巧才能在编译器中进行完整的类型检查。
首先,将subclassError
方法改为return未知类型,这样我们就可以独立定义类型签名了:
/**
* @param {string} name
* @param {(function(new:Error)?)=} parent
* @param {(Function?)=} constructor
* @return {?}
**/
function subclassError (name, parent, constructor) {}
接下来,我们为FooError
添加一个存根定义,以便编译器能够理解类型信息。然后我们实际给subclassError
方法的结果赋值
/**
* @constructor
* @extends {Error}
* @param {Error} err
* @param {number} bar
* @param {number} baz
**/
var FooError = function(err, bar, baz) {};
FooError = subclassError('FooError', null, function (bar, baz) {
this.message = "invalid bar: '" + bar + "', (using '" + baz + "')";
});
现在我们从编译器得到正确的类型检查
// The compiler will warn that FooError is called with
// the wrong number of arguments
new FooError(new Error());