sovraccarico di costruzione della dattiloscritto

voti
216

Qualcuno ha fatto il costruttore sovraccarico a macchina. A pagina 64 della specifica del linguaggio (v 0.8), ci sono affermazioni che descrivono sovraccarichi costruttore, ma non c'era alcun codice di esempio dato.

Sto provando una dichiarazione di classe veramente di base in questo momento; sembra che questo,

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

Quando correva con BoxSample.ts TSC, si getta fuori una definizione costruttore duplicato - che è ovvio. Ogni aiuto è apprezzato.

È pubblicato 03/10/2012 alle 06:48
fonte dall'utente
In altre lingue...                            


13 risposte

voti
190

Dattiloscritto consente di dichiarare sovraccarichi, ma si può avere una sola applicazione e che l'attuazione deve avere una firma che è compatibile con tutti i sovraccarichi. Nel tuo esempio, questo può facilmente essere fatto con un parametro opzionale come in,

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 && obj.x || 0
        this.y = obj && obj.y || 0
        this.height = obj && obj.height || 0
        this.width = obj && obj.width || 0;
    }   
}

o due overload con un costruttore più generale come a,

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();
    constructor(obj: IBox); 
    constructor(obj?: any) {    
        this.x = obj && obj.x || 0
        this.y = obj && obj.y || 0
        this.height = obj && obj.height || 0
        this.width = obj && obj.width || 0;
    }   
}
Risposto il 03/10/2012 a 07:14
fonte dall'utente

voti
63

Si noti che è anche possibile aggirare la mancanza di un sovraccarico a livello di attuazione attraverso parametri di default a macchina, ad esempio:

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 = {x:0,y:0, height:0, width:0}) {    
        this.x = obj.x;
        this.y = obj.y;
        this.height = obj.height;
        this.width = obj.width;
    }   
}

Edit: A partire dal 5 dicembre '16, vedi la risposta di Benson per una soluzione più elaborato che consente una maggiore flessibilità.

Risposto il 09/10/2012 a 07:29
fonte dall'utente

voti
48

Per quanto riguarda costruttore sovraccarica un'alternativa sarebbe quella di attuare le sovraccarichi aggiuntivi come metodi factory statici . Penso che sia più leggibile e meno confusione di verificare le proprie argomentazioni di chiamata. Qui c'è un semplice esempio:

class Person {
    static fromData(data: PersonData) {
        let { first, last, birthday, gender = 'M' } = data 
        return new this(
            `${last}, ${first}`,
            calculateAge(birthday),
            gender
        )
    }

    constructor(
        public fullName: string,
        public age: number,
        public gender: 'M' | 'F'
    ) {}
}

interface PersonData {
    first: string
    last: string
    birthday: string
    gender?: 'M' | 'F'
}


let personA = new Person('Doe, John', 31, 'M')
let personB = Person.fromData({
    first: 'John',
    last: 'Doe',
    birthday: '10-09-1986'
})

Metodo sovraccarico a macchina non è per vero , diciamo, in quanto richiederebbe troppo codice generato dal compilatore e il core team cercare di evitare che a tutti i costi. Attualmente il motivo principale per il metodo sovraccarico di essere presenti sulla lingua è quello di fornire un modo per scrivere le dichiarazioni per le biblioteche con argomenti magici nella loro API. Dal momento che è necessario fare tutto il sollevamento pesante da soli per gestire diverse serie di argomentazioni non vedo molto vantaggio nell'utilizzo di sovraccarichi, invece di metodi separati.

Risposto il 31/07/2016 a 21:08
fonte dall'utente

voti
38

Nota: questo è stato semplificato e aggiornato per riflettere 2017/04/13 dattiloscritto 2.1, vedere la storia per dattiloscritto 1.8 risposta.

Sembra che si desidera che il parametro oggetto deve essere facoltativa, e anche ciascuna delle proprietà nell'oggetto di essere facoltativa. Nell'esempio, come previsto, non è richiesta la sintassi sovraccarico. Ho voluto sottolineare alcune pratiche negative in alcune delle risposte qui. Certo, non è la più piccola espressione possibile della sostanza scrivere box = { x: 0, y: 87, width: 4, height: 0 }, ma questo fornisce tutte le sottigliezze che alludono codice che si può desiderare dalla classe come descritto. Questo esempio consente di chiamare una funzione con uno, alcuni, tutti, o nessuno dei parametri e ancora ottenere i valori di default.

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

     // The class can work double-duty as the interface here since they are identical
     // Alternately, reference your own interface, e.g.:  `...BoxI = {} as BoxI` 
     constructor(obj: Box = {} as Box) {

         // Define the properties of the incoming `obj` object here. 
         // Setting a default value with the `= 0` syntax is optional for each parameter
         let {
             x = 0,
             y = 0,
             height = 0,
             width = 0
         } = obj;

         /** Use jsdoc comments here for inline ide auto-documentation */
         this.x = x;
         this.y = y;
         this.height = height;
         this.width = width;
     }
 }

Questo è un modo molto sicuro per scrivere i parametri che non possono avere tutte le proprietà dell'oggetto definito. A questo punto è possibile scrivere in modo sicuro uno di questi:

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

 // Correctly reports error in TypeScript, and in js, box6.z is undefined
const box6 = new Box({z:0});  

Compilato, si vede che i parametri facoltativi veramente sono opzionali, che evita le insidie di un ampiamente utilizzato (ma incline errore) di sintassi fallback di var = isOptional || default;controllando contro void 0, che è una scorciatoia per undefined:

L'output compilato

var Box = (function () {
    function Box(obj) {
        if (obj === void 0) { obj = {}; }
        var _a = obj.x, 
        x = _a === void 0 ? 1 : _a,
        _b = obj.y,
        y = _b === void 0 ? 1 : _b,
        _c = obj.height,
        height = _c === void 0 ? 1 : _c,
        _d = obj.width,
        width = _d === void 0 ? 1 : _d;
        this.x = x;
        this.y = y;
        this.height = height;
        this.width = width;
    }
    return Box;
}());

Addendum: Impostazione valori di default: il modo sbagliato

L' ||operatore (o)

Prendere in considerazione il pericolo di ||/ o operatori quando si impostano valori di ripristino di default come mostrato in alcune altre risposte. Questo codice illustra il modo sbagliato di impostare i valori predefiniti. È possibile ottenere risultati imprevisti quando si valuta contro Falsey valori come 0, '', null, undefined, falso, NaN:

var myDesiredValue = 0;
var result = myDesiredValue || 2;

// This test will correctly report a problem with this setup.
console.assert(myDesiredValue === result && result === 0, 'Result should equal myDesiredValue. ' + myDesiredValue + ' does not equal ' + result);

Object.assign (questo, obj)

Nel mio test, utilizzando ES6 dattiloscritto destrutturato oggetto / può essere quasi il 90% più veloce di Object.assign . Utilizzando un parametro destrutturato consente solo i metodi e le proprietà che avete assegnato all'oggetto. Ad esempio, si consideri questo metodo:

class BoxTest {
    public x?: number = 1;

    constructor(obj: BoxTest = {} as BoxTest) {
        Object.assign(this, obj);
    }
}

Se un altro utente non stava usando dattiloscritto e ha tentato di inserire un parametro che non gli apparteneva, per esempio, si potrebbe provare a mettere un zimmobile

var box = new BoxTest({x: 0, y: 87, width: 4, height: 0, z: 7});

// This test will correctly report an error with this setup. `z` was defined even though `z` is not an allowed property of obj.
console.assert(typeof box.z === 'undefined')
Risposto il 05/12/2016 a 14:30
fonte dall'utente

voti
32

So che questa è una vecchia questione, ma di nuovo in 1.4 è tipi unione; utilizzare questi per tutti i sovraccarichi e di funzione (compresi i costruttori). Esempio:

class foo {
    private _name: any;
    constructor(name: string | number) {
        this._name = name;
    }
}
var f1 = new foo("bar");
var f2 = new foo(1);
Risposto il 04/02/2015 a 18:28
fonte dall'utente

voti
20

Aggiornamento (8 giugno 2017): guyarad e snolflake fare punti validi nei loro commenti qui sotto per la mia risposta. Suggerirei i lettori guardano le risposte di Benson , Joe e snolflake che hanno risposte migliore della mia.

Risposta originale (27 gennaio 2014)

Un altro esempio di come realizzare costruttore di sovraccarico:

class DateHour {

  private date: Date;
  private relativeHour: number;

  constructor(year: number, month: number, day: number, relativeHour: number);
  constructor(date: Date, relativeHour: number);
  constructor(dateOrYear: any, monthOrRelativeHour: number, day?: number, relativeHour?: number) {
    if (typeof dateOrYear === "number") {
      this.date = new Date(dateOrYear, monthOrRelativeHour, day);
      this.relativeHour = relativeHour;
    } else {
      var date = <Date> dateOrYear;
      this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
      this.relativeHour = monthOrRelativeHour;
    }
  }
}

Fonte: http://mimosite.com/blog/post/2013/04/08/Overloading-in-TypeScript

Risposto il 27/01/2014 a 17:02
fonte dall'utente

voti
3

Nel caso in cui un parametro tipizzato optional è abbastanza buono, si consideri il seguente codice che compie lo stesso senza ripetere le proprietà o la definizione di un'interfaccia:

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

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

Tenete a mente questo assegnerà tutte le proprietà passarono a track, vigilia se non sono definiti in Track.

Risposto il 06/11/2016 a 00:22
fonte dall'utente

voti
1

È possibile gestire questo da:

import { assign } from 'lodash'; // if you don't have lodash use Object.assign
class Box {
    x: number;
    y: number;
    height: number;
    width: number;
    constructor(obj: Partial<Box> = {}) {    
         assign(this, obj);
    }
}

Parziale renderà i vostri campi (x, y, altezza, larghezza) optional, consentendo a più costruttori

ad esempio: si può fare new Box({x,y})senza l'altezza e la larghezza.

Il = {}gestirà valore falsy come undefined, null, ecc, e allora si può farenew Box()

Risposto il 11/09/2018 a 09:36
fonte dall'utente

voti
1

Un'altra versione, come a @ di ShinNoNoir codice, utilizzando i valori predefiniti e la sintassi diffusione:

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

    constructor({x, y, height, width}: IBox = { x: 0, y: 0, height: 0, width: 0 }) {
        this.x = x;
        this.y = y;
        this.height = height;
        this.width = width;
    }
}
Risposto il 30/11/2016 a 05:11
fonte dall'utente

voti
0

Io uso la seguente alternativa per ottenere predefinite params / opzionali e "tipo-di-sovraccarico" costruttori con numero variabile di params:

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

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

Io so che non è il codice più bella di sempre, ma ci si abitua ad esso. Non c'è bisogno per la nuova interfaccia di rete e consente agli utenti privati, che non è possibile quando si utilizza l'interfaccia.

Risposto il 20/09/2019 a 14:28
fonte dall'utente

voti
0

In realtà potrebbe essere troppo tardi per questa risposta, ma ora si può fare questo:

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

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

così invece di metodi statici che si può fare quanto sopra. Spero che vi aiuterà !!!

Risposto il 26/05/2019 a 23:31
fonte dall'utente

voti
0

Siamo in grado di simulare il sovraccarico costruttore utilizzando guardie

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" })
Risposto il 27/03/2019 a 00:18
fonte dall'utente

voti
0

Si dovrebbe avuto in mente che ...

contructor ()

costruttore (un qualsiasi, b: ogni, c: qualsiasi)

E 'lo stesso di

new () o un nuovo ( "a", "b", "c")

così

costruttore (a:? ogni, b: ogni, c: qualsiasi) è la stessa sopra ed è più flessibile ...

nuovo () o nuovo ( "a") o un nuovo ( "a", "b") o nuovo ( "a", "b", "c")

Risposto il 02/06/2018 a 14:15
fonte dall'utente

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more