【问题标题】:Implement function overloading in typescript在打字稿中实现函数重载
【发布时间】:2019-01-24 09:14:43
【问题描述】:

我知道 typescript 和 javascript 不支持函数重载。

而且我正在研究一种绕路方法来像这个函数重载一样工作。

我的情况如下。

第一:

最后一个和第一个参数是固定的。

public A(arg1:number, arg2:number, argLast:any){

}

public A(arg1:number, arg2:number, arg3:Array<any>, argLast:any){

}

第二:

有函数是否重载的指示器。

当然,和上面的例子一样,是可以的,但是我必须通过一个新的接口来创建它,所以它不适合我的情况。

我尝试过各种函数重载方法。

我也通过 john resig 博客实现了它。

(https://johnresig.com/blog/javascript-method-overloading/)

下面的代码是我通过上面的博客做的一个例子。

function addMethod (object, name, fn) {
  var old = object[ name ]
  object[ name ] = function () {
    if (fn.length === arguments.length) {
      return fn.apply(this, arguments)
    } else if (typeof old === 'function') {
      return old.apply(this, arguments)
    }
  }
}

export class Users{
  find(...arg: any[]){
    Users.prototype['findOVF'](arg)
  }
}
addMethod(Users.prototype, 'findOVF', function () {
  console.log('ARG 0')
})
addMethod(Users.prototype, 'findOVF', function (name:string, age:number) {
  console.log('ARG 2')
})
addMethod(Users.prototype, 'findOVF', function (first_name:string, last_name:string,age:number) {
  console.log('ARG 3')
})

var users = new Users()
users.find() 
users.find('John',19) 
users.find('John', 'Resig', 19) 

当我使用这个方法时,我用参数(... arg)来调用函数。

我已经尝试实现了下面博客的所有方法。

(https://blog.mariusschulz.com/2016/08/18/function-overloads-in-typescript)

public A(arg1:number, arg2:number, argLast:any){

}

public A(arg1:number, arg2:number, arg3:Array<any>|null, argLast:any){

}

如果我以这种方式实现函数重载,每次调用 A 函数时都会出错。这不是真正的函数重载。

但是我还没有找到同时实现这两个元素的方法。

我想知道这对于打字稿语法是不可能的,还是有其他可能性。

感谢您看到我笨拙的英语。

【问题讨论】:

  • 我不太清楚什么不起作用。您能否发布一个完整的示例,其中包含您想要工作但无法正常工作或无法按预期工作的代码?
  • 好的。我现在就发帖。但是,写作会很长。希望你能理解。
  • 我试图描述我尝试的方法。我也有一个问题......对不起。

标签: function typescript overloading


【解决方案1】:

您可以在 typescript 中创建重载,但所有重载都有一个实现,您可以自行区分它们。最简单的解决方案,如果你的方法都只是通过参数的数量来区分是这样的:

class User { }
export class Users {
    find(): User;
    find(name: string, age: number): User;
    find(first_name: string, last_name: string, age: number): User
    find(...args: [any?, any?, any?]): User {
        if (args.length == 0) {
            return null as any;
        } else if (args.length == 1) {
            let [name, age, _]: [string?, number?, any?] = args;
            console.log(`${name}, ${age}`);
            return null as any;
        } else if (args.length == 2){
            let [first_name, last_name, age]: [string?, string?, number?] = args;
            console.log(`${first_name}, ${last_name}, ${age}`);
            return null as any;
        } else {
            throw "Not implemented";
        }
    }
}

Playground link

上述解决方案保留了调用站点类型的安全性,您的解决方案没有,因为在您的示例中find 的参数是any[]

您可以通过定义一个函数来使用更自动化的方法,该函数将从函数数组中创建一个重载函数,但是这种额外的复杂性值得您来判断。

type UnionToIntersection<U> =
    (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never

function overloads<TThis>(){
    return function<T extends Array<(this: TThis, ...args: any[]) => any>>(...fns: T): UnionToIntersection<T[number]> {
        return function (this: TThis, ...args: any[]) {
            for (var fn of fns) {
                if (fn.length === args.length) {
                    return fn.apply(this, args);
                }
            }
            throw "Not implemented";
        } as any
    }
}

class User { }
export class Users {
    member: string = "M"
    find = overloads<Users>()(
        function () {
            console.log('ARG 0');
            this.member // this is Users 
        },
        function (name: string, age: number) {
            console.log('ARG 2')
        },
        function (first_name: string, last_name: string, age: number) {
            console.log('ARG 3')
        }
    );
}

var users = new Users()
users.find('John', 19)
users.find('John', 'Resig', 19) 

Playground link

或者将函数分配给原型而不是实例的版本:

export class Users {
    member: string = "M"
}

let find = overloads<Users>()(
    function () {
        console.log('ARG 0');
        this.member // this is Users 
    },
    function (name: string, age: number) {
        console.log('ARG 2')
    },
    function (first_name: string, last_name: string, age: number) {
        console.log('ARG 3')
    }
);
export interface Users {
    find: typeof find;
}
Users.prototype.find = find;

Playground link

【讨论】:

  • 谢谢您的热心回答!但我有一些错误:rest 参数必须是数组类型。而 JSDoc 类型只能在文档 cmets 中使用。
  • @naiad 你用的是什么版本的打字稿,上面的代码适用于3.0
  • @naiad 第一个版本适用于任何版本的打字稿,并且是最容易理解的版本,对于简单的重载,我会使用那个版本
  • 我的 IDE 是 Visual Studio 代码,当我编写“tsc -v”命令时:版本 3.0.1
  • @naiad 为所有示例添加了游乐场链接,它们都可以正常工作,并且应该在您的 IDE 中也可以工作。
猜你喜欢
  • 1970-01-01
  • 2020-05-20
  • 1970-01-01
  • 2017-01-17
  • 2017-01-04
  • 2019-07-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多