TypeScript 函数重载

问题描述 投票:0回答:5

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 overloading
5个回答
366
投票

当您在 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”来决定要做什么。


265
投票

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

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

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


69
投票

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

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

26
投票

打字稿中的函数重载:

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

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

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


24
投票

什么是函数重载?

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


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

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

更多信息:

© www.soinside.com 2019 - 2024. All rights reserved.