2016-11-10 5 views
1

ich eine Klasse an Typ-Skript haben:Typoskript - Pass gesamte Objekt Konstruktor

export class Child { 
    name:string; 
    age:number; 
} 

Ich möchte Klasseninstanzen zwingen, nur Eigenschaften, die Klassendeklaration hat.

Zum Beispiel, wenn ich von Feuerbasis ein Objekt erhalten:

myFirebaseService.getChild(id).then(function(child){ 
    var currentChild = new Child(child); 
}) 

Also, wenn das Objekt: {name: "ben", Farbe: "db"}, mag ich das Ergebnis sein:

currentChild = {"name":"ben"} 

Becouse "Farbe" ist nicht Feld von "Kind".

Ich habe versucht, dieses:

export class Child { 
    name:string; 
    age:number; 

    constructor(tempChild:Child = null) { 
    if (tempChild){ 
     for (var prop in tempChild) { 
     this[prop] = tempChild[prop]; 
     } 
    } 
    } 
} 

Aber es hilft nicht. "currentChild" ruft alle Felder ab und hängt sie an die Klasseninstanz an.

(Natürlich kann ich den folgenden Code verwenden:

export class Child { 
    name:string; 
    age:number; 

    constructor(tempChild:Child = null) { 
    if (tempChild){ 
     this.nam = tempChild.name; 
     this.age =tempChild.ageÏ; 
    } 
    } 
} 

, aber meine Wahrheit Klasse hat viele Felder, und ich möchte kurzen Code)

+0

Ich denke, dass neue [keyof] (https://github.com/Microsoft/TypeScript/pull/11929) Funktion von Typescript 2.1 für Sie praktisch sein könnte. –

+0

@AlekseyL. Nein, weil sein Problem ein Runtime-Problem ist. –

Antwort

2

Sie nicht haben viele Auswahlmöglichkeiten hier, weil die Elementdefinitionen, die Sie in der Klasse vor dem Konstruktor machen, nicht in Javascript übersetzt werden, der Compiler lässt sie aus:

class Child { 
    name: string; 
    age: number; 

    constructor() { 
     this.name = "name"; 
    } 
} 

Compiliert in:

var Child = (function() { 
    function Child() { 
     this.name = "name"; 
    } 
    return Child; 
}()); 

Wie Sie sehen können, das name Mitglied der einzige ist, und selbst wird es nur, wenn zugewiesen verwendet.

Da Sie die Namen der Mitglieder im laufenden Betrieb benötigen, müssen Sie sie beiseite gesetzt haben, zum Beispiel in einem Array:

class Child { 
    private static MEMBERS = ["name", "age"]; 

    name: string; 
    age: number; 

    constructor(tempChild: Child = null) { 
     if (tempChild) { 
      for (var prop in tempChild) { 
       if (Child.MEMBERS.indexOf(props) >= 0) { 
        this[prop] = tempChild[prop]; 
       } 
      } 
     } 
    } 
} 

Das ist nicht sehr komfortabel zu arbeiten, so dass Sie kann Dekorateure verwenden.
Zum Beispiel:

function member(cls: any, name: string) { 
    if (!cls.constructor.MEMBERS) { 
     cls.constructor.MEMBERS = []; 
    } 

    cls.constructor.MEMBERS.push(name); 
} 

function isMember(cls: any, name: string): boolean { 
    return cls.MEMBERS[name] != null; 
} 

class Child { 
    @member 
    name: string; 

    @member 
    age: number; 

    constructor(tempChild: Child = null) { 
     if (tempChild) { 
      for (var prop in tempChild) { 
       if (isMember(Child, prop)) { 
        this[prop] = tempChild[prop]; 
       } 
      } 
     } 
    } 
} 

(code in playground)

Es ist nicht getestet ist, so bin ich es funktioniert nicht sicher, aber wenn Sie diesen Weg gehen entscheiden, dann ist es das meiste, was Sie brauchen.

-1

Meiner Meinung nach wäre der sauberste Weg, Ihre Klasseninstanzen aus einem beliebigen Objekt zu erstellen, die Destrukturierung.Sie haben noch Zuweisungen für alle Felder, aber Sie haben (sehr sauber) Kontrolle darüber, was passiert, wenn das Feld nicht existiert, und auch, welche Felder Sie Ihre Klassen Felder zuweisen:

export class Child { 
    name:string 
    age:number 

    constructor({name = 'default name', age = 0} = {}) { 
    this.name = name 
    this.age = age 
    } 
} 

Nun ist diese lässt Sie erstellen Ihre Instanzen von Object s oder any s oder irgendwelchen Teil Objektliterale, aber als Literale verwenden es werden Ihnen zusätzliche Sachen nicht zulassen, hinzufügen, die wie scheint, ist, was Sie brauchen:

const c0 = new Child({} as any /* as Object works as well */) 
const c1 = new Child({}) // Literal, will be using defaults 
const c2 = new Child() // No argument, using defaults only 
const c3 = new Child({ name: 'a', age: 1 }) 
const c4 = new Child({ name: 'b', foo: 'bar'}) // error with foo 

generiert js prüfen wird alles, was Sie manuell überprüfen würden:

define(["require", "exports"], function (require, exports) { 
    "use strict"; 
    var Child = (function() { 
     function Child(_a) { 
      var _b = _a === void 0 ? {} : _a, _c = _b.name, name = _c === void 0 ? 'default name' : _c, _d = _b.age, age = _d === void 0 ? 0 : _d; 
      this.name = name; 
      this.age = age; 
     } 
     return Child; 
    }()); 
    exports.Child = Child; 
}); 

Versuchen Sie und sehen Sie in der playground, was daraus generiert wird!