首页 文章

使用空构造函数的TypeScript构造函数重载

提问于
浏览
27

为什么不允许 TypeScript 中有单独的 constructor 定义?
要有例如两个 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;
}

因此,我需要在第一个构造函数中不需要的参数之后放置 ? .

为什么我不能这样写呢?

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;
}

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

而且,如果我需要一个空的构造函数,事情变得更加怪异,因为我需要用 ? 标记每个参数 .

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

为什么 TypeScriptC#Python 这样的常用语言不同?

我希望它能像这样工作 .

constructor() {

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

因此,您可以传递无参数或必须传递所有参数 .

4 回答

  • 18

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

    想象一下这样:

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

    以这种方式思考, overload_constructor 无法调用 implementation_constructor ,除非 nameage 是可选的 .

    另请参阅Basarat 's answer, the implementation isn'暴露供类型检查器公开使用(尽管在运行时它是JS中使用的"real"构造函数) . 如果您只想允许 ()(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;
    }
    

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

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

    不是,例如:

    new Foo(1, "a")
    
  • 22

    最后一个函数重载仅用于实现,不公开 . 如下所示:

    class Foo{
        constructor()
        constructor(id?: number) {
        }
    }
    
    const foo1 = new Foo();
    const foo2 = new Foo(123); // Error! : not public
    

    如果您希望 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
    

    原因是TypeScript尝试不为函数重载执行花哨的代码生成(传统语言使用名称修改来执行此操作,例如C)

    因此,您可以传递无参数或必须传递参数 .

    实际上你可以使最终的重载是可选的,但是没有公共的重载是可选的 . 请考虑以下示例:

    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

    您可以使用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);
        }
      }
    }
    
  • -1

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

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

相关问题