przeciążenie Konstruktor w maszynopisie

głosy
216

Czy ktoś zrobił konstruktora przeciążeniu na maszynie. Na stronie 64 specyfikacji języka (v 0.8), istnieją wypowiedzi opisujące przeciążeń konstruktora, ale nie było żadnych przykładowy kod podany.

Staram się naprawdę podstawową deklarację klasy teraz; To wygląda tak,

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

Kiedy biegł z BoxSample.ts TSC, to wyrzuca duplikat definicji konstruktora - co jest oczywiste. Każda pomoc jest mile widziana.

Utwórz 03/10/2012 o 06:48
źródło użytkownik
W innych językach...                            


13 odpowiedzi

głosy
190

Maszynopis pozwala zadeklarować przeciążeń, ale można mieć tylko jedną implementację i że realizacja musi mieć podpis, który jest kompatybilny ze wszystkimi przeciążeniami. W przykładzie, można to łatwo zrobić za pomocą opcjonalnego parametru jak w,

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

lub dwa przeciążeń z ogólną konstruktora jak w,

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;
    }   
}
Odpowiedział 03/10/2012 o 07:14
źródło użytkownik

głosy
63

Zauważ, że można też obejść braku przeciążenia na poziomie wdrażania przez domyślnymi parametrami pismem maszynowym, na przykład:

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: Od 5 grudnia '16, patrz odpowiedź Bensona na dokładniejszym rozwiązaniem, które pozwala na większą elastyczność.

Odpowiedział 09/10/2012 o 07:29
źródło użytkownik

głosy
48

Odnośnie konstruktora przeciąża jeden alternatywą byłoby wdrożenie dodatkowych przeciążeń jak statycznych metod fabrycznych . Myślę, że jest to bardziej czytelne i mniej kłopotliwe niż testowanie swoich argumentów wywołania. Oto prosty przykład:

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

Metoda przeciążenia w maszynopisie nie jest prawdziwe , powiedzmy, gdyż wymagałoby to zbyt dużo kompilator wygenerowany kod i podstawowy zespół starają się uniknąć za wszelką cenę. Obecnie głównym powodem przeciążenia metody być obecne na języku jest zapewnienie drogę do napisania oświadczenia dla bibliotek z magicznych argumentów w ich API. Ponieważ trzeba zrobić wszystko, podnoszenia ciężkich samodzielnie obsługiwać różne zestawy argumentów nie widzę wiele korzyści w użyciu przeciążenia zamiast oddzielone metod.

Odpowiedział 31/07/2016 o 21:08
źródło użytkownik

głosy
38

Uwaga: ta została uproszczona i aktualizowane w celu odzwierciedlenia 4/13/2017 maszynopis 2.1, zobaczyć historię maszynopis 1,8 odpowiedź.

Brzmi to jak chcesz parametr obiekt będzie opcjonalne, a także każdy z właściwości obiektu, aby być opcjonalne. Na przykład, jak przewidziano, składnia przeciążenie nie jest potrzebne. Chciałem zwrócić uwagę na pewne złe praktyki w niektórych odpowiedzi tutaj. To prawda, nie jest to najmniejsza możliwa ekspresja zasadniczo pisanie box = { x: 0, y: 87, width: 4, height: 0 }, ale zapewnia to cały kod sugerując subtelności, czego można chcieć od klasy, jak to opisano. Przykład ten pozwala wywołać funkcję z jednym, niektóre, wszystkie lub żaden z parametrów i nadal uzyskać wartości domyślne.

 /** @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;
     }
 }

Jest to bardzo bezpieczny sposób pisać o parametrach, które nie mogą mieć wszystkie właściwości obiektu zdefiniowane. Teraz można bezpiecznie pisać każdy z nich:

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

Skompilowany, widać, że naprawdę opcjonalne parametry są opcjonalne, że unika pułapek powszechnie stosowane (ale podatne na błędy) awaryjna składnia var = isOptional || default;sprawdzając przed void 0, co jest skrótem dla undefined:

Wyjście skompilowanego

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

Uzupełnienie: Ustawianie wartości domyślnych: w niewłaściwy sposób

||Operatora (OR)

Rozważyć ryzyko ||/ lub operatorzy podczas ustawiania domyślnych wartości zastępczych, jak pokazano w niektórych innych odpowiedzi. Ten kod poniżej przedstawia w niewłaściwy sposób, aby ustawić domyślne. Można uzyskać niespodziewane wyniki przy ocenie przed falsey wartościach takich jak 0, „”, null, niezdefiniowanej, fałszywych, 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 (to obj)

W moich testach, z wykorzystaniem ES6 / maszynopis destrukturyzowaną obiekt może być prawie 90% szybciej niż Object.assign . Korzystanie z destrukturyzowaną parametr pozwala jedynie metody i właściwości już przypisane do obiektu. Na przykład, należy rozważyć tę metodę:

class BoxTest {
    public x?: number = 1;

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

Jeśli inny użytkownik nie używał maszynopis i próbował umieścić parametr, który nie należał, powiedzmy, mogą spróbować oddanie zmienia

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')
Odpowiedział 05/12/2016 o 14:30
źródło użytkownik

głosy
32

Wiem, że jest to stara sprawa, ale jest nowy w 1.4 Typy Unii; korzystać z tych wszystkich przeciążeń funkcyjnych (w tym konstruktorów). Przykład:

class foo {
    private _name: any;
    constructor(name: string | number) {
        this._name = name;
    }
}
var f1 = new foo("bar");
var f2 = new foo(1);
Odpowiedział 04/02/2015 o 18:28
źródło użytkownik

głosy
20

Update (08 czerwca 2017): guyarad i snolflake dokonać ważnych punktów w uwagach poniżej mojej odpowiedzi. Polecam czytelnikom spojrzeć na odpowiedzi od Benson , Joe i snolflake którzy mają lepsze odpowiedzi niż moja.

Oryginalny Answer (27 stycznia 2014 roku)

Innym przykładem, jak osiągnąć konstruktora przeciążenie:

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

Źródło: http://mimosite.com/blog/post/2013/04/08/Overloading-in-TypeScript

Odpowiedział 27/01/2014 o 17:02
źródło użytkownik

głosy
3

W przypadku, gdy opcjonalny, wpisany parametr jest wystarczająco dobry, należy rozważyć następujący kod, który robi to samo bez powtarzania właściwości lub zdefiniowanie interfejsu:

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

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

Należy pamiętać, że przypisze wszystkie właściwości przekazywane w trackEve jeśli nie są one określone na Track.

Odpowiedział 06/11/2016 o 00:22
źródło użytkownik

głosy
1

Można sobie z tym poradzić poprzez:

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

Częściowa uczyni swoje pola (x, y, wysokość, szerokość) składniki ewentualne, pozwalając wielu konstruktorów

np: można zrobić new Box({x,y})bez wysokości i szerokości.

= {}Zajmie wartość falsy takich jak nieokreślonej, null itp, a następnie można zrobićnew Box()

Odpowiedział 11/09/2018 o 09:36
źródło użytkownik

głosy
1

Inna wersja jak do użytkownika @ ShinNoNoir kodu, używając wartości domyślnych i składni spread:

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;
    }
}
Odpowiedział 30/11/2016 o 05:11
źródło użytkownik

głosy
0

Używam następującą alternatywę, aby uzyskać default / opcjonalne params i „kind-of-przeciążony” konstruktorzy o zmiennej liczbie params:

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

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

Wiem, że nie jest to najładniejszy kod kiedykolwiek, ale jeden przyzwyczaja się do niego. Nie ma potrzeby stosowania dodatkowego interfejsu i pozwala członków prywatnych, co nie jest możliwe przy użyciu interfejsu.

Odpowiedział 20/09/2019 o 14:28
źródło użytkownik

głosy
0

Właściwie to może być za późno na tej odpowiedzi, ale można to zrobić teraz:

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

więc zamiast metod statycznych można wykonać wyżej. Mam nadzieję, że to pomoże !!!

Odpowiedział 26/05/2019 o 23:31
źródło użytkownik

głosy
0

Możemy symulować przeciążenie konstruktora używając strażników

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" })
Odpowiedział 27/03/2019 o 00:18
źródło użytkownik

głosy
0

Należy pamiętać, że miał ...

contructor ()

konstruktor (a: każdy b: każdy c: każdy)

To samo z

Nowy () lub nowy ( "a", "b", "c"),

A zatem

konstruktor (A: każdy b: każdy c: występuje) są takie same powyżej, jest bardziej elastyczny ...

Nowy () lub nowy ( "a") lub nową ( "a", "b") lub nową ( "a", "b", "c"),

Odpowiedział 02/06/2018 o 14:15
źródło użytkownik

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