TypeScript 语言规范的第 6.3 节讨论了函数重载,并给出了如何实现它的具体示例。但是,如果我尝试这样的事情:
export class LayerFactory {
constructor (public styleFactory: Symbology.StyleFactory) {
// Init...
}
createFeatureLayer (userContext: Model.UserContext, mapWrapperObj: MapWrapperBase): any {
throw new Error('not implemented');
}
createFeatureLayer(layerName: string, style: any): any {
throw new Error('not implemented');
}
}
即使函数参数的类型不同,我也会收到编译器错误,指示重复的标识符。即使我向第二个 createFeatureLayer 函数添加附加参数,我仍然会收到编译器错误。请出主意。
当您在 TypeScript 中重载时,您只有一个具有多个签名的实现。
class Foo {
myMethod(a: string);
myMethod(a: number);
myMethod(a: number, b: string);
myMethod(a: string | number, b?: string) {
alert(a.toString());
}
}
TypeScript 仅将三个重载识别为方法调用的可能签名,而不是实际的实现。实现签名必须与所有重载兼容。
在你的情况下,我个人会使用两种不同名称的方法,因为参数没有足够的通用性,这使得方法体可能需要有很多“ifs”来决定要做什么。
这可能是因为,当两个函数都编译为 JavaScript 时,它们的签名完全相同。由于 JavaScript 没有类型,我们最终创建了两个采用相同数量参数的函数。因此,TypeScript 限制我们创建此类函数。
TypeScript 支持基于参数数量的重载,但与 OO 语言相比,要遵循的步骤有点不同。在回答另一个SO问题时,有人用一个很好的例子解释了它:方法重载?.
基本上,我们正在做的是,我们只创建一个函数和许多声明,以便 TypeScript 不会给出编译错误。当这段代码被编译为 JavaScript 时,具体的功能将是可见的。由于可以通过传递多个参数来调用 JavaScript 函数,因此它可以正常工作。
您可以通过将函数声明为具有多个调用签名的类型来声明重载函数:
interface IFoo
{
bar: {
(s: string): number;
(n: number): string;
}
}
然后是以下内容:
var foo1: IFoo = ...;
var n: number = foo1.bar('baz'); // OK
var s: string = foo1.bar(123); // OK
var a: number[] = foo1.bar([1,2,3]); // ERROR
函数的实际定义必须是单数,并在内部对其参数执行适当的调度。
例如,使用一个类(可以实现
IFoo
,但不是必须):
class Foo
{
public bar(s: string): number;
public bar(n: number): string;
public bar(arg: any): any
{
if (typeof(arg) === 'number')
return arg.toString();
if (typeof(arg) === 'string')
return arg.length;
}
}
这里有趣的是,
any
形式被更具体的类型覆盖所隐藏。
var foo2: new Foo();
var n: number = foo2.bar('baz'); // OK
var s: string = foo2.bar(123); // OK
var a: number[] = foo2.bar([1,2,3]); // ERROR
根据维基百科(和许多编程书籍),方法/函数重载的定义如下:
在某些编程语言中,函数重载或方法 重载是创建相同功能的多个功能的能力 名称具有不同的实现。调用重载函数 将运行适合该函数的特定实现 调用的上下文,允许一个函数调用执行不同的操作 任务取决于上下文。
在打字稿中,我们不能根据参数的数量和类型来调用同一函数的不同实现。这是因为当 TS 编译为 JS 时,JS 中的函数有以下特点:
因此,从严格意义上讲,可以说 TS 函数重载不存在。但是,您可以在 TS 代码中执行一些操作来完美模仿函数重载。
这是一个例子:
function add(a: number, b: number, c: number): number;
function add(a: number, b: number): any;
function add(a: string, b: string): any;
function add(a: any, b: any, c?: any): any {
if (c) {
return a + c;
}
if (typeof a === 'string') {
return `a is ${a}, b is ${b}`;
} else {
return a + b;
}
}
TS 文档将此称为方法重载,我们基本上所做的就是向 TS 编译器提供多个方法签名(可能的参数和类型的描述)。现在 TS 可以判断我们在编译时是否正确调用了函数,如果我们错误地调用了函数,则给我们一个错误。
函数重载或方法重载是能够创建同名的多个函数和不同的实现(维基百科)
此功能在 JS 中是不可能的 - 在多个声明的情况下将采用最后定义的函数:
function foo(a1, a2) { return `${a1}, ${a2}` }
function foo(a1) { return `${a1}` } // replaces above `foo` declaration
foo(42, "foo") // "42"
重载是一个编译时构造,对 JS 运行时没有影响:
function foo(s: string): string // overload #1 of foo
function foo(s: string, n: number): number // overload #2 of foo
function foo(s: string, n?: number): string | number {/* ... */} // foo implementation
如果使用上面的代码(比 JS 更安全),则会触发重复的实现错误。 TS 按自上而下的顺序选择第一个拟合重载,因此重载按从最具体到最广泛的顺序排序。
重载类方法类型的使用方式与函数重载类似:
class LayerFactory {
createFeatureLayer(a1: string, a2: number): string
createFeatureLayer(a1: number, a2: boolean, a3: string): number
createFeatureLayer(a1: string | number, a2: number | boolean, a3?: string)
: number | string { /*... your implementation*/ }
}
const fact = new LayerFactory()
fact.createFeatureLayer("foo", 42) // string
fact.createFeatureLayer(3, true, "bar") // number
可能存在截然不同的重载,因为函数实现与所有重载签名兼容 - 由编译器强制执行。
更多信息: