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函数中添加了一个额外的参数,我仍然会得到一个编译器错误。想法,请。


这可能是因为,当两个函数被编译成JavaScript时,它们的签名完全相同。由于JavaScript没有类型,我们最终创建了两个具有相同数量参数的函数。所以TypeScript限制我们创建这样的函数。

TypeScript支持基于参数数量的重载,但如果与OO语言相比,所遵循的步骤略有不同。在回答另一个SO问题时,有人用一个很好的例子来解释:方法重载?

基本上,我们所做的是,我们只创建一个函数和一些声明,这样TypeScript就不会给出编译错误。当这段代码被编译成JavaScript时,只会看到具体的函数。由于JavaScript函数可以通过传递多个参数来调用,所以它可以正常工作。


当你在TypeScript中重载时,你只有一个具有多个签名的实现。

class Foo {
    myMethod(a: string);
    myMethod(a: number);
    myMethod(a: number, b: string);
    myMethod(a: string | number, b?: string) {
        alert(a.toString());
    }
}

只有这三个重载被TypeScript识别为方法调用的可能签名,而不是实际的实现。实现签名必须与所有重载兼容。

在你的情况下,我个人会使用两个不同名称的方法,因为参数中没有足够的共性,这使得方法主体可能需要有很多“如果”来决定做什么。


你可以通过声明一个重载函数为具有多个调用签名的类型:

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

作为对其他人的提醒,我观察到至少从WebPack为Angular 2编译的TypeScript中可以看出,你会悄悄地覆盖而不是重载方法。

myComponent {
  method(): { console.info("no args"); },
  method(arg): { console.info("with arg"); }
}

调用:

myComponent.method()

似乎是执行带有参数的方法,无声地忽略无参数的版本,输出:

with arg

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

不同的重载是可能的,因为函数实现兼容所有的重载签名——由编译器强制执行。

更多信息:

操场上的样品 超载时该做什么和不该做什么