Javascript 有没有办法在 TypeScript 中进行方法重载?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12688275/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is there a way to do method overloading in TypeScript?
提问by Void-995
Is there a way to do method overloading in TypeScript language?
有没有办法在 TypeScript 语言中进行方法重载?
I want to achieve something like this:
我想实现这样的目标:
class TestClass {
someMethod(stringParameter: string): void {
alert("Variant #1: stringParameter = " + stringParameter);
}
someMethod(numberParameter: number, stringParameter: string): void {
alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
}
}
var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");
Here is an example of what I don't want to do (I really hate that part of overloading hack in JS):
这是我不想做的一个例子(我真的很讨厌在 JS 中重载 hack 的那部分):
class TestClass {
private someMethod_Overload_string(stringParameter: string): void {
// A lot of code could be here... I don't want to mix it with switch or if statement in general function
alert("Variant #1: stringParameter = " + stringParameter);
}
private someMethod_Overload_number_string(numberParameter: number, stringParameter: string): void {
alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
}
private someMethod_Overload_string_number(stringParameter: string, numberParameter: number): void {
alert("Variant #3: stringParameter = " + stringParameter + ", numberParameter = " + numberParameter);
}
public someMethod(stringParameter: string): void;
public someMethod(numberParameter: number, stringParameter: string): void;
public someMethod(stringParameter: string, numberParameter: number): void;
public someMethod(): void {
switch (arguments.length) {
case 1:
if(typeof arguments[0] == "string") {
this.someMethod_Overload_string(arguments[0]);
return;
}
return; // Unreachable area for this case, unnecessary return statement
case 2:
if ((typeof arguments[0] == "number") &&
(typeof arguments[1] == "string")) {
this.someMethod_Overload_number_string(arguments[0], arguments[1]);
}
else if ((typeof arguments[0] == "string") &&
(typeof arguments[1] == "number")) {
this.someMethod_Overload_string_number(arguments[0], arguments[1]);
}
return; // Unreachable area for this case, unnecessary return statement
}
}
}
var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");
testClass.someMethod("string for v#3", 54321);
回答by svick
According to the specification, TypeScript does support method overloading, but it's quite awkward and includes a lot of manual work checking types of parameters. I think it's mostly because the closest you can get to method overloading in plain JavaScript includes that checking too and TypeScript tries to not modify actual method bodies to avoid any unnecessary runtime performance cost.
根据规范,TypeScript 确实支持方法重载,但它非常笨拙,并且包含大量手动工作检查参数类型。我认为这主要是因为在纯 JavaScript 中最接近方法重载的方法也包括检查,并且 TypeScript 试图不修改实际的方法主体以避免任何不必要的运行时性能成本。
If I understand it correctly, you have to first write a method declaration for each of the overloads and then onemethod implementation that checks its arguments to decide which overload was called. The signature of the implementation has to be compatible with all of the overloads.
如果我理解正确,您必须首先为每个重载编写一个方法声明,然后编写一个方法实现来检查其参数以确定调用哪个重载。实现的签名必须与所有重载兼容。
class TestClass {
someMethod(stringParameter: string): void;
someMethod(numberParameter: number, stringParameter: string): void;
someMethod(stringOrNumberParameter: any, stringParameter?: string): void {
if (stringOrNumberParameter && typeof stringOrNumberParameter == "number")
alert("Variant #2: numberParameter = " + stringOrNumberParameter + ", stringParameter = " + stringParameter);
else
alert("Variant #1: stringParameter = " + stringOrNumberParameter);
}
}
回答by Fenton
Update for clarity. Method overloading in TypeScript is a useful feature insofar as it allows you to create type definitions for existing libraries with an API that needs to be represented.
为清楚起见更新。TypeScript 中的方法重载是一项有用的功能,因为它允许您使用需要表示的 API 为现有库创建类型定义。
When writing your own code, though, you may well be able to avoid the cognitive overhead of overloads using optional or default parameters. This is the more readable alternative to method overloads and also keeps your API honest as you'll avoid creating overloads with unintuitive ordering.
但是,在编写自己的代码时,您很可能能够避免使用可选或默认参数的重载的认知开销。这是方法重载的更具可读性的替代方案,并且还可以使您的 API 保持诚实,因为您将避免使用不直观的顺序创建重载。
The general law of TypeScript overloads is:
TypeScript 重载的一般规律是:
You can usually achieve the same thing with optional, or default parameters - or with union types, or with a bit of object-orientation.
您通常可以使用可选参数或默认参数实现相同的功能 - 或者使用联合类型,或者使用一些面向对象的方法。
The Actual Question
实际问题
The actual question asks for an overload of:
实际问题要求重载:
someMethod(stringParameter: string): void {
someMethod(numberParameter: number, stringParameter: string): void {
Now even in languages that support overloads with separate implementations (note: TypeScript overloads share a single implementation) - programmers are advices to provide consistency in ordering. This would make the signatures:
现在,即使在支持具有单独实现的重载的语言中(注意:TypeScript 重载共享单个实现) - 程序员建议提供排序的一致性。这将使签名:
someMethod(stringParameter: string): void {
someMethod(stringParameter: string, numberParameter: number): void {
The stringParameter
is always required, so it goes first. You could write this as a working TypeScript overload:
将stringParameter
始终是必需的,所以先行。你可以把它写成一个有效的 TypeScript 重载:
someMethod(stringParameter: string): void;
someMethod(stringParameter: string, numberParameter: number): void;
someMethod(stringParameter: string, numberParameter?: number): void {
if (numberParameter != null) {
// The number parameter is present...
}
}
But following the law of TypeScript overloads, we can delete the overload signatures and all our tests will still pass.
但是按照 TypeScript 重载的法则,我们可以删除重载签名,我们所有的测试仍然会通过。
someMethod(stringParameter: string, numberParameter?: number): void {
if (numberParameter != null) {
// The number parameter is present...
}
}
The Actual Question, In the Actual Order
实际问题,按实际顺序
If you were determined to persist with the original order, the overloads would be:
如果您决定坚持原始顺序,则重载将是:
someMethod(stringParameter: string): void;
someMethod(numberParameter: number, stringParameter: string): void;
someMethod(a: string | number, b?: string | number): void {
let stringParameter: string;
let numberParameter: number;
if (typeof a === 'string') {
stringParameter = a;
} else {
numberParameter = a;
if (typeof b === 'string') {
stringParameter = b;
}
}
}
Now that's a lot of branching to work out where to put the parameters, but you really wanted to preserve this order if you are reading this far... but wait, what happens if we apply the law of TypeScript overloads?
现在有很多分支来确定在哪里放置参数,但是如果你读到这里,你真的想保留这个顺序……但是等等,如果我们应用 TypeScript 重载定律会发生什么?
someMethod(a: string | number, b?: string | number): void {
let stringParameter: string;
let numberParameter: number;
if (typeof a === 'string') {
stringParameter = a;
} else {
numberParameter = a;
if (typeof b === 'string') {
stringParameter = b;
}
}
}
Enough Branching Already
足够的分支已经
Of course, given the amount of type checking we need to do... maybe the best answer is simply to have two method:
当然,考虑到我们需要做的类型检查的数量......也许最好的答案就是有两种方法:
someMethod(stringParameter: string): void {
this.someOtherMethod(0, stringParameter);
}
someOtherMethod(numberParameter: number, stringParameter: string): void {
//...
}
回答by nicopolyptic
I wish. I want this feature too but TypeScript needs to be interoperable with untyped JavaScript which doesn't have overloaded methods. i.e. If your overloaded method is called from JavaScript then it can only get dispatched to one method implementation.
我希望。我也想要这个功能,但 TypeScript 需要与没有重载方法的无类型 JavaScript 互操作。即如果您的重载方法是从 JavaScript 调用的,那么它只能被分派到一个方法实现。
There\s a few relevant discussions on codeplex. e.g.
有一些关于 codeplex 的相关讨论。例如
https://typescript.codeplex.com/workitem/617
https://typescript.codeplex.com/workitem/617
I still think TypeScript should generate all the if'ing and switching so we wouldn't need to do it.
我仍然认为 TypeScript 应该生成所有的 if'ing 和切换,所以我们不需要这样做。
回答by u3758939
Why not to use optional property defined interfaceas the function argument..
为什么不使用可选属性定义的接口作为函数参数..
For the case in this question, using an inline interface defined with some optional properties only could directly make code like something below:
对于这个问题中的情况,使用定义了一些可选属性的内联接口只能直接制作如下代码:
class TestClass {
someMethod(arg: { stringParameter: string, numberParameter?: number }): void {
let numberParameterMsg = "Variant #1:";
if (arg.numberParameter) {
numberParameterMsg = `Variant #2: numberParameter = ${arg.numberParameter},`;
}
alert(`${numberParameterMsg} stringParameter = ${arg.stringParameter}`);
}
}
var testClass = new TestClass();
testClass.someMethod({ stringParameter: "string for v#1" });
testClass.someMethod({ numberParameter: 12345, stringParameter: "string for v#2" });
Because overloading provided in TypeScript is, as mentioned in others' comments, just a list of function's different signatures without supporting corresponding implementation codes like other static languages. So the implementation still have to be done in only one function body, which makes the usage of function overloading in Typescript not as comfortable as such languages supporting the real overloading feature.
因为 TypeScript 提供的重载,正如其他人的评论中提到的,只是一个函数不同签名的列表,并不像其他静态语言那样支持相应的实现代码。所以实现仍然只需要在一个函数体中完成,这使得在 Typescript 中函数重载的使用不像支持真正重载功能的语言那样舒服。
However, there is still many new and convenient stuffs provided in typescript which is not available in legacy programming language, where optional property support in an anonymous interface is such an approach to meet the comfortable zone from the legacy function overloading, I think.
然而,打字稿中仍然提供了许多新的和方便的东西,这些东西在遗留编程语言中是不可用的,我认为,匿名接口中的可选属性支持是一种满足遗留函数重载舒适区的方法。
回答by Igor
If there are a lot of variations of method overloads, another way is just to create a class with all your args inside. So you can pass only parameter you want in any order.
如果方法重载有很多变体,另一种方法是创建一个包含所有参数的类。所以你可以按任何顺序只传递你想要的参数。
class SomeMethodConfig {
stringParameter: string;
numberParameter: number;
/**
*
*/
constructor(stringParameter: string = '012', numberParameter?: number) { // different ways to make a param optional
this.numberParameter = 456; // you can put a default value here
this.stringParameter = stringParameter; // to pass a value throw the constructor if necessary
}
}
Also you can create a constructor with default values and/or pass some mandatory arguments. Then just use like this:
您也可以使用默认值创建构造函数和/或传递一些必需参数。然后像这样使用:
const config = new SomeMethodConfig('text');
config.numberParameter = 123; // initialize an optional parameter only if you want to do it
this.SomeMethod(config);
回答by Gyan
Javascript does not have any concept of overloading. Typescript is not c# or Java.
Javascript 没有任何重载的概念。打字稿不是 c# 或 Java。
But you can implement overloading in Typescript.
但是您可以在 Typescript 中实现重载。
Read this post http://www.gyanparkash.in/function-overloading-in-typescript/
阅读这篇文章 http://www.gyanparkash.in/function-overloading-in-typescript/