592 Stimmen

Konstruktorüberladung in TypeScript

Hat jemand Konstruktor Überladen in TypeScript getan. Auf Seite 64 der Sprachspezifikation (v 0.8) gibt es Anweisungen, die Konstruktorüberladungen beschreiben, aber es wurde kein Beispielcode angegeben.

Ich probiere gerade eine ganz einfache Klassendeklaration aus, die so aussieht,

interface IBox {    
    x : number;
    y : number;
    height : number;
    width : number;
}

class Box {
    public x: number;
    public y: number;
    public height: number;
    public width: number;

    constructor(obj: IBox) {    
        this.x = obj.x;
        this.y = obj.y;
        this.height = obj.height;
        this.width = obj.width;
    }   

    constructor() {
        this.x = 0;
        this.y = 0;
        this.width = 0;
        this.height = 0;
    }
}

Wenn mit tsc BoxSample.ts ausgeführt wird, wirft es eine doppelte Konstruktordefinition aus - was offensichtlich ist. Jede Hilfe ist willkommen.

4voto

parliament Punkte 19682

Für den Fall, dass ein optionaler, typisierter Parameter ausreicht, können Sie den folgenden Code verwenden, der das Gleiche erreicht, ohne die Eigenschaften zu wiederholen oder eine Schnittstelle zu definieren:

export class Track {
   public title: string;
   public artist: string;
   public lyrics: string;

   constructor(track?: Track) {
     Object.assign(this, track);
   }
}

Denken Sie daran, dass dadurch alle Eigenschaften, die in track auch wenn sie nicht auf Track .

2voto

miguel savignano Punkte 979

Wir können eine Konstruktorüberladung simulieren, indem wir Wachen

interface IUser {
  name: string;
  lastName: string;
}

interface IUserRaw {
  UserName: string;
  UserLastName: string;
}

function isUserRaw(user): user is IUserRaw {
  return !!(user.UserName && user.UserLastName);
}

class User {
  name: string;
  lastName: string;

  constructor(data: IUser | IUserRaw) {
    if (isUserRaw(data)) {
      this.name = data.UserName;
      this.lastName = data.UserLastName;
    } else {
      this.name = data.name;
      this.lastName = data.lastName;
    }
  }
}

const user  = new User({ name: "Jhon", lastName: "Doe" })
const user2 = new User({ UserName: "Jhon", UserLastName: "Doe" })

1voto

yN. Punkte 1677

Ich verwende die folgende Alternative, um standardmäßige/optionale Parameter und "irgendwie überladene" Konstruktoren mit variabler Anzahl von Parametern zu erhalten:

private x?: number;
private y?: number;

constructor({x = 10, y}: {x?: number, y?: number}) {
 this.x = x;
 this.y = y;
}

Ich weiß, es ist nicht der schönste Code überhaupt, aber man gewöhnt sich daran. Man braucht kein zusätzliches Interface und es erlaubt private Mitglieder, was bei Verwendung des Interface nicht möglich ist.

1voto

Radu Linu Punkte 927

Hier ist ein funktionierendes Beispiel und Sie müssen beachten, dass jeder Konstruktor mit mehr Feldern die zusätzlichen Felder als optional .

class LocalError {
  message?: string;
  status?: string;
  details?: Map<string, string>;

  constructor(message: string);
  constructor(message?: string, status?: string);
  constructor(message?: string, status?: string, details?: Map<string, string>) {
    this.message = message;
    this.status = status;
    this.details = details;
  }
}

1voto

rustyBucketBay Punkte 4182

Wie in der Antwort von @Benson kommentiert, habe ich dieses Beispiel in meinem Code verwendet, und ich fand es sehr nützlich. Allerdings fand ich mit dem Object is possibly 'undefined'.ts(2532) Fehler, als ich versuchte, Berechnungen mit den Typen meiner Klassenvariablen durchzuführen, da das Fragezeichen dazu führt, dass sie vom Typ AssignedType | undefined . Auch wenn der undefinierte Fall bei der späteren Ausführung oder mit dem Compiler-Typ enforce behandelt wird <AssignedType> Ich konnte den Fehler nicht beheben, also konnte ich die Argumente nicht optional machen, sondern habe einen separaten Typ für die Argumente mit den Fragezeichen params und die Klassenvariablen ohne die Fragezeichen erstellt. Umständlich, aber funktioniert.

Hier ist der Originalcode, der den Fehler in der Klassenmethode() aufweist, siehe unten:

/** @class */

class Box {
  public x?: number;
  public y?: number;
  public height?: number;
  public width?: number;

  // The Box class can work double-duty as the interface here since they are identical
  // If you choose to add methods or modify this class, you will need to
  // define and reference a new interface for the incoming parameters object 
  // e.g.:  `constructor(params: BoxObjI = {} as BoxObjI)` 
  constructor(params: Box = {} as Box) {
    // Define the properties of the incoming `params` object here. 
    // Setting a default value with the `= 0` syntax is optional for each parameter
    const {
      x = 0,
      y = 0,
      height = 1,
      width = 1,
    } = params;

    //  If needed, make the parameters publicly accessible
    //  on the class ex.: 'this.var = var'.
    /**  Use jsdoc comments here for inline ide auto-documentation */
    this.x = x;
    this.y = y;
    this.height = height;
    this.width = width;
  }

  method(): void {
    const total = this.x + 1; // ERROR. Object is possibly 'undefined'.ts(2532)
  }
}

const box1 = new Box();
const box2 = new Box({});
const box3 = new Box({ x: 0 });
const box4 = new Box({ x: 0, height: 10 });
const box5 = new Box({ x: 0, y: 87, width: 4, height: 0 });

Die Variable kann also nicht in den Methoden der Klasse verwendet werden. Wenn das zum Beispiel so korrigiert wird:

method(): void {
    const total = <number> this.x + 1;
}

Jetzt erscheint dieser Fehler:

Argument of type '{ x: number; y: number; width: number; height: number; }' is not 
assignable to parameter of type 'Box'.
Property 'method' is missing in type '{ x: number; y: number; width: number; height: 
number; }' but required in type 'Box'.ts(2345)

Als ob das ganze Argumentationsbündel nicht mehr optional wäre.

Wenn also ein Typ mit optionalen Argumenten erstellt wird und die Klassenvariablen aus dem optionalen Bereich entfernt werden, erreiche ich, was ich will: die Argumente sind optional und können in den Klassenmethoden verwendet werden. Unten der Lösungscode:

type BoxParams = {
  x?: number;
  y?: number;
  height?: number;
  width?: number;
}

/** @class */
class Box {
  public x: number;
  public y: number;
  public height: number;
  public width: number;

  // The Box class can work double-duty as the interface here since they are identical
  // If you choose to add methods or modify this class, you will need to
  // define and reference a new interface for the incoming parameters object 
  // e.g.:  `constructor(params: BoxObjI = {} as BoxObjI)` 
  constructor(params: BoxParams = {} as BoxParams) {
    // Define the properties of the incoming `params` object here. 
    // Setting a default value with the `= 0` syntax is optional for each parameter
    const {
      x = 0,
      y = 0,
      height = 1,
      width = 1,
    } = params;

    //  If needed, make the parameters publicly accessible
    //  on the class ex.: 'this.var = var'.
    /**  Use jsdoc comments here for inline ide auto-documentation */
    this.x = x;
    this.y = y;
    this.height = height;
    this.width = width;
  }

  method(): void {
    const total = this.x + 1;
  }
}

const box1 = new Box();
const box2 = new Box({});
const box3 = new Box({ x: 0 });
const box4 = new Box({ x: 0, height: 10 });
const box5 = new Box({ x: 0, y: 87, width: 4, height: 0 });

Ich freue mich über Kommentare von allen, die sich die Zeit nehmen, zu lesen und zu verstehen, worauf ich hinauswollte.

Vielen Dank im Voraus.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X