在打字稿中实现函数重载
Posted
技术标签:
【中文标题】在打字稿中实现函数重载【英文标题】: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 函数时都会出错。这不是真正的函数重载。
但是我还没有找到同时实现这两个元素的方法。
我想知道这对于打字稿语法是不可能的,还是有其他可能性。
感谢您看到我笨拙的英语。
【问题讨论】:
我不太清楚什么不起作用。您能否发布一个完整的示例,其中包含您想要工作但无法正常工作或无法按预期工作的代码? 好的。我现在就发帖。但是,写作会很长。希望你能理解。 我试图描述我尝试的方法。我也有一个问题......对不起。 【参考方案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 中也可以工作。以上是关于在打字稿中实现函数重载的主要内容,如果未能解决你的问题,请参考以下文章