TypeScript Constructor Overload with Empty Constructor

前端 未结 4 1877
春和景丽
春和景丽 2020-12-15 03:30

Why is it not allowed to have separate constructor definitions in TypeScript?
To have e.g. two constructors<

相关标签:
4条回答
  • 2020-12-15 04:05

    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:number to be available publically ofcourse you can add another overload:

    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++)

    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
    
    0 讨论(0)
  • 2020-12-15 04:08

    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_constructor could not call implementation_constructor unless name and age are optional.

    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:

    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")
    
    0 讨论(0)
  • 2020-12-15 04:08

    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)
        }
    }
    
    0 讨论(0)
  • 2020-12-15 04:17

    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.

    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);
        }
      }
    }
    
    0 讨论(0)
提交回复
热议问题