334

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

4

6 回答 6

282

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

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

TypeScript 仅将这三个重载识别为方法调用的可能签名,而不是实际的实现。

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

打字稿 1.4

从 TypeScript 1.4 开始,您通常可以使用联合类型消除对重载的需求。上面的例子可以更好地表达为:

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

的类型a是“要么stringnumber”。

于 2012-11-03T19:50:31.303 回答
238

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

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

基本上,我们所做的是,我们只创建一个函数和许多声明,以便 TypeScript 不会产生编译错误。当这段代码被编译成 JavaScript 时,单独的具体函数将是可见的。由于可以通过传递多个参数来调用 JavaScript 函数,因此它可以正常工作。

于 2012-11-03T19:49:29.897 回答
54

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

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
于 2014-06-14T16:49:11.577 回答
14

打字稿中的函数重载:

根据维基百科(和许多编程书籍),方法/函数重载的定义如下:

在某些编程语言中,函数重载或方法重载是创建具有不同实现的多个同名函数的能力。对重载函数的调用将运行适合于调用上下文的该函数的特定实现,允许一个函数调用根据上下文执行不同的任务。

在打字稿中,我们不能根据参数的数量和类型来调用同一函数的不同实现。这是因为 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 可以判断我们在编译期间是否正确调用了函数,如果调用不正确,则会给我们一个错误。

于 2020-03-07T18:34:42.827 回答
10

通常什么是函数重载?

函数重载或方法重载是创建具有不同实现的多个同名函数的能力(维基百科


什么是 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

由于函数实现与所有重载签名兼容 - 由编译器强制执行,因此可能存在截然不同的重载。

更多信息:

于 2020-05-10T11:34:32.177 回答
0

作为对其他人的提醒,我观察到至少正如 WebPack 为 Angular 2 编译的 TypeScript 所表明的那样,你悄悄地得到 overWRITTEN 而不是 overLOADED 方法。

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

来电:

myComponent.method()

似乎使用参数执行该方法,默默地忽略无参数版本,输出:

with arg
于 2016-10-03T14:57:18.653 回答