web-dev-qa-db-ja.com

空のコンストラクターによるTypeScriptコンストラクターのオーバーロード

なぜconstructorTypeScriptで個別に定義できないのですか?
two 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;
}

そのため、パラメータなしで渡すことも、すべてのパラメータを渡す必要があります。

33
Daniel Hitzel

コンストラクターの実装は、すべてのオーバーロードコンストラクターによって呼び出されるためです。 (技術的には、実行時には、さまざまなオーバーロード引数シグネチャで呼び出されるコンストラクター関数が1つだけあります。)

次のように想像してください:

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

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

このように考えると、overload_constructorは、nameおよびageがオプションでない限り、implementation_constructorを呼び出すことができませんでした。

また、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;
}

実装ではすべてのパラメーターはオプションですが、コンパイル時に署名は公開されないため、これらの呼び出しのみを使用できます。

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

ではない、例えば:

new Foo(1, "a")
23
Aaron Beall

最後の関数オーバーロードは実装でのみ使用され、公開されていません。これを以下に示します。

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
27
basarat

これを解決するには、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);
    }
  }
}
0
PeeWee2201