如何重载具有可变参数的函数
How to overload a function with variable arguments
我目前有一个采用可变参数的翻译管道
@Pipe({name: 'translate', pure: true})
export class TranslationPipe {
constructor(private service: TranslationService) {}
transform(key: string, ...params: (number|string)[]): string {
// The translation service takes an array
return this._service.translate(key, params);
}
}
对于像error.message=You have {0} of {1} tries left
这样的消息,它在模板中的调用方式如下
{{ 'error.message' | translate : currentTry : totalTriesAllowed }}
但是,我们现在有一个情况,组件将键和替换参数作为一个数组(因为它不知道可能有多少,因为键是由调用者提供的)而我不知道不知道为该方法创建重载的好方法。
我确实尝试过从模板传播参数,但那不是有效的语法
{{ translationKey | translate : ...translationArgs }}
为了能够完成这项工作,我想我需要像下面这样的重载,以便翻译管道也可以将数组作为第一个参数而不是单独的参数传递
transform(key: string, params: (string|number)[]): string;
transform(key: string, ...params: (string|number)[]): string;
但是,我一直未能找到支持此重载的良好实现。这是我目前所在的位置。
type ArryayOfStringOrNumber = (string|number)[];
export class TranslationPipe {
// ERROR: Overload signature is not compatible with function implementation
transform(key: string, params: ArryayOfStringOrNumber): string;
transform(key: string, ...params: ArryayOfStringOrNumber): string;
transform(key: string, ...params: ArryayOfStringOrNumber): any {
if (params[0] instanceof Array) {
// ERROR: The left-hand side of an 'instanceof' expression must
// be of type 'any', an object type or a type parameter.
params = params[0] as ArryayOfStringOrNumber;
}
return this._service.translate(key, params as ArryayOfStringOrNumber);
}
}
问题是实现重载的函数必须接受一个对象数组,其中每个对象都可以是 (string|number)[]
类型或这些对象的数组,即 ((string|number)[])[]
transform(key: string, ...params: (ArryayOfStringOrNumber|(string|number))[]): any {
if (params[0] instanceof Array) {
params = params[0] as ArryayOfStringOrNumber;
}
return this._service.translate(key, params as ArryayOfStringOrNumber);
}
我刚刚遇到了类似的问题,我所做的是拆分展开数组的第一个可能的参数,使其成为联合类型,并在必要时将其添加到展开数组中。
结果有点像这样:
foo(bar: Bar): void;
foo(...bazs: Array<Baz>): void;
foo(barOrBaz: Bar | Baz, ...bazsRest: Array<Baz>): void {
if (barOrBaz instanceof Bar) {
let bar = barOrBaz;
// first overload
} else {
let bazs = [barOrBaz, ...bazsRest];
// second overload
}
}
所以在你的情况下,实现也可以这样写:
transform(key: string, paramsFirst: string | number | ArrayOfStringOrNumber, ...paramsRest: ArrayOfStringOrNumber): string {
let params = paramsFirst instanceof Array ? paramsFirst : [paramsFirst, ...paramsRest];
return this._service.translate(key, params);
}
我目前有一个采用可变参数的翻译管道
@Pipe({name: 'translate', pure: true})
export class TranslationPipe {
constructor(private service: TranslationService) {}
transform(key: string, ...params: (number|string)[]): string {
// The translation service takes an array
return this._service.translate(key, params);
}
}
对于像error.message=You have {0} of {1} tries left
这样的消息,它在模板中的调用方式如下
{{ 'error.message' | translate : currentTry : totalTriesAllowed }}
但是,我们现在有一个情况,组件将键和替换参数作为一个数组(因为它不知道可能有多少,因为键是由调用者提供的)而我不知道不知道为该方法创建重载的好方法。
我确实尝试过从模板传播参数,但那不是有效的语法
{{ translationKey | translate : ...translationArgs }}
为了能够完成这项工作,我想我需要像下面这样的重载,以便翻译管道也可以将数组作为第一个参数而不是单独的参数传递
transform(key: string, params: (string|number)[]): string;
transform(key: string, ...params: (string|number)[]): string;
但是,我一直未能找到支持此重载的良好实现。这是我目前所在的位置。
type ArryayOfStringOrNumber = (string|number)[];
export class TranslationPipe {
// ERROR: Overload signature is not compatible with function implementation
transform(key: string, params: ArryayOfStringOrNumber): string;
transform(key: string, ...params: ArryayOfStringOrNumber): string;
transform(key: string, ...params: ArryayOfStringOrNumber): any {
if (params[0] instanceof Array) {
// ERROR: The left-hand side of an 'instanceof' expression must
// be of type 'any', an object type or a type parameter.
params = params[0] as ArryayOfStringOrNumber;
}
return this._service.translate(key, params as ArryayOfStringOrNumber);
}
}
问题是实现重载的函数必须接受一个对象数组,其中每个对象都可以是 (string|number)[]
类型或这些对象的数组,即 ((string|number)[])[]
transform(key: string, ...params: (ArryayOfStringOrNumber|(string|number))[]): any {
if (params[0] instanceof Array) {
params = params[0] as ArryayOfStringOrNumber;
}
return this._service.translate(key, params as ArryayOfStringOrNumber);
}
我刚刚遇到了类似的问题,我所做的是拆分展开数组的第一个可能的参数,使其成为联合类型,并在必要时将其添加到展开数组中。
结果有点像这样:
foo(bar: Bar): void;
foo(...bazs: Array<Baz>): void;
foo(barOrBaz: Bar | Baz, ...bazsRest: Array<Baz>): void {
if (barOrBaz instanceof Bar) {
let bar = barOrBaz;
// first overload
} else {
let bazs = [barOrBaz, ...bazsRest];
// second overload
}
}
所以在你的情况下,实现也可以这样写:
transform(key: string, paramsFirst: string | number | ArrayOfStringOrNumber, ...paramsRest: ArrayOfStringOrNumber): string {
let params = paramsFirst instanceof Array ? paramsFirst : [paramsFirst, ...paramsRest];
return this._service.translate(key, params);
}