TypeScript语言规范的第6.3节讨论了函数重载,并给出了如何实现函数重载的具体示例。然而,如果我尝试这样做:
export class LayerFactory {
constructor (public styleFactory: Symbology.StyleFactory) { }
createFeatureLayer (userContext : Model.UserContext, mapWrapperObj : MapWrapperBase) : any {
throw "not implemented";
}
createFeatureLayer(layerName : string, style : any) : any {
throw "not implemented";
}
}
我得到一个编译器错误指示重复的标识符,即使函数参数是不同的类型。即使我在第二个createFeatureLayer函数中添加了一个额外的参数,我仍然会得到一个编译器错误。想法,请。
你可以通过声明一个重载函数为具有多个调用签名的类型:
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
当你在TypeScript中重载时,你只有一个具有多个签名的实现。
class Foo {
myMethod(a: string);
myMethod(a: number);
myMethod(a: number, b: string);
myMethod(a: string | number, b?: string) {
alert(a.toString());
}
}
只有这三个重载被TypeScript识别为方法调用的可能签名,而不是实际的实现。实现签名必须与所有重载兼容。
在你的情况下,我个人会使用两个不同名称的方法,因为参数中没有足够的共性,这使得方法主体可能需要有很多“如果”来决定做什么。
typescript中的函数重载:
根据维基百科(以及许多编程书籍),方法/函数重载的定义如下:
在某些编程语言中,函数重载或方法重载
重载是创建相同的多个函数的能力
使用不同的实现命名。调用重载函数
是否运行该函数的特定实现
调用的上下文,允许一个函数调用执行不同的
任务取决于上下文。
在typescript中,我们不能根据参数的数量和类型来调用同一个函数的不同实现。这是因为当TS被编译成JS时,JS中的函数具有以下特征:
JavaScript函数定义不为参数指定数据类型
JavaScript函数在调用时不检查参数的数量
因此,严格地说,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可以判断我们在编译期间是否正确地调用了函数,如果调用不正确则会给出一个错误。
什么是函数重载?
函数重载或方法重载是用不同的实现创建多个同名函数的能力(Wikipedia)
什么是JS中的函数重载?
这个特性在JS中是不可能的——在多次声明的情况下使用最后一个定义的函数:
function foo(a1, a2) { return `${a1}, ${a2}` }
function foo(a1) { return `${a1}` } // replaces above `foo` declaration
foo(42, "foo") // "42"
... 那么TS呢?
重载是一个编译时构造,对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以自顶向下的顺序选择第一个拟合重载,因此重载从最具体到最广泛进行排序。
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
不同的重载是可能的,因为函数实现兼容所有的重载签名——由编译器强制执行。
更多信息:
操场上的样品
超载时该做什么和不该做什么
你可以通过声明一个重载函数为具有多个调用签名的类型:
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