带有空构造函数的 TypeScript 构造函数重载

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/35998629/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 07:00:39  来源:igfitidea点击:

TypeScript Constructor Overload with Empty Constructor

constructortypescript

提问by Daniel Hitzel

Why is it not allowed to have separate constructordefinitions in TypeScript?
To have e.g. two constructors, I need to write my code like this.

为什么不允许constructorTypeScript 中有单独的定义?
要拥有例如两个constructors,我需要像这样编写代码。

constructor(id: number)
constructor(id: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Thereby I need to put ?after the parameters that are not required in the first constructor.

因此,我需要将?第一个构造函数中不需要的参数放在后面。

Why can't I write it like this?

为什么我不能这样写?

constructor(id: number) {
    this.id = id;
}

constructor(id: number, name: string, surname: string, email: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

So that for both constructors all parameters are mandatory.

因此,对于两个构造函数,所有参数都是必需的。

Moreover, if I need to have an empty constructor things get even weirder, since I need to mark every parameter with a ?.

此外,如果我需要一个空的构造函数,事情会变得更奇怪,因为我需要用?.

constructor()
constructor(id?: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Why does TypeScriptdiffers from common languages like C#or Pythonhere?

为什么TypeScript与像C#Python这里这样的常见语言不同?

I would expect it to work like this.

我希望它像这样工作。

constructor() {

}
constructor(id: number, name: string, surname: string, email: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

So you can pass none parameter or must pass all parameters.

所以你可以不传递参数或必须传递所有参数。

采纳答案by Aaron Beall

Because your constructor implementation is called by all your overload constructors. (Technically, at runtime there's only one constructor function that gets called with the various overload argument signatures.)

因为您的构造函数实现被所有重载构造函数调用。(从技术上讲,在运行时,只有一个构造函数被各种重载参数签名调用。)

Imagine it like this:

想象一下:

overload_constructor(id:string) {
    implementation_constructor(id);
}

implementation_constructor(id:string, name?:string, age?:number) {
    // ...
}

Thinking of it this way, overload_constructorcould not call implementation_constructorunless nameand ageare optional.

以这种方式思考,除非和是可选的,overload_constructor否则不能调用。implementation_constructornameage

Also see Basarat's answer, the implementation isn't exposed for public usage by the type checker (though at runtime it's the "real" constructor used in JS). If you want to only allow (), (id), or (id, name, surname, email)as the only valid call signatures you would do it like this:

另请参阅 Basarat 的答案,类型检查器不会公开该实现以供公共使用(尽管在运行时它是 JS 中使用的“真实”构造函数)。如果您只想允许(), (id), 或(id, name, surname, email)作为唯一有效的调用签名,您可以这样做:

constructor()
constructor(id: number)
constructor(id: number, name: string, surname: string, email: string)
constructor(id?: number, name?: string, surname?: string, email?: string) {
    this.id = id;
    this.name = name;
    this.surname = surname;
    this.email = email;
}

Note that in the implementation all parameters are optional, but that signature is not exposed when compiling and you can only use these these calls:

请注意,在实现中,所有参数都是可选的,但编译时不会公开该签名,您只能使用这些调用:

new Foo()
new Foo(1)
new Foo(1, "a", "b", "c")

Not, for example:

不是,例如:

new Foo(1, "a")

回答by basarat

The last function overload is only used in the implementation and not available publicly. This is shown below:

最后一个函数重载只在实现中使用,不公开。这如下所示:

class Foo{
    constructor()
    constructor(id?: number) {
    }
}

const foo1 = new Foo();
const foo2 = new Foo(123); // Error! : not public

If you want id:numberto be available publically ofcourse you can add another overload:

如果你想id:number公开可用,你可以添加另一个重载:

class Foo{
    constructor()
    constructor(id: number)
    constructor(id?: number) {
    }
}

const foo1 = new Foo();
const foo2 = new Foo(123); // Okay
const foo3 = new Foo('hello'); // Error: Does not match any public overload

The reason is that TypeScript tries not to do fancy code generation for function overloading (traditional languages do this using name mangling e.g. C++)

原因是 TypeScript 尽量不为函数重载做花哨的代码生成(传统语言使用名称修饰来做到这一点,例如 C++)

So you can pass none parameter or must pass parameters.

所以你可以不传递参数或必须传递参数。

Actually you can make the final overload optional but none of the public ones as optional. Consider the following example:

实际上,您可以将最终重载设为可选,但不能将公共重载设为可选。考虑以下示例:

class Foo{  
    constructor(id: number, name:string)
    constructor(name:string)
    constructor(idOrName?: number|string, name?:string) {
    }
}

const foo1 = new Foo('name'); // Okay
const foo2 = new Foo(123); // Error: you must provide a name if you use the id overload
const foo3 = new Foo(123,'name'); // Okay

回答by PeeWee2201

You can use Builder pattern to solve this. Even in C# or Python, it quickly becomes a better approach as the number of constructor arguments grows.

您可以使用 Builder 模式来解决这个问题。即使在 C# 或 Python 中,随着构造函数参数数量的增加,它也很快成为一种更好的方法。

class Foo {
  constructor(public id: number, public name: string, public surname: string, public email: string) {
  }
  static Builder = class {
    id: number = NaN;
    name: string = null;
    surname: string = null;
    email: string = null;
    Builder() {
    }
    build(): Foo {
      return new Foo(this.id, this.name, this.surname, this.email);
    }
  }
}

回答by Rodolfo Patane

If you use static methods to implement overload contructors, see.

如果您使用静态方法来实现重载构造函数,请参阅。

export class User implements IUser {
     constructor(
        private _id: string,
        private _name: string,
        private _email: string,
      ) {}
    static New(jsonUser:string){
        return new User(
            JSON.parse(jsonUser).id,
            JSON.parse(jsonUser).name,
            JSON.parse(jsonUser).email)
    }
}