Wie initiiert man eine neue Klasse in TS auf diese Weise (Beispiel in C#, um zu zeigen, was ich will):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
Wie initiiert man eine neue Klasse in TS auf diese Weise (Beispiel in C#, um zu zeigen, was ich will):
// ... some code before
return new MyClass { Field1 = "ASD", Field2 = "QWE" };
// ... some code after
Aktualisiert am 12.07.2016: Typescript 2.1 führt Mapped Types ein und bietet Partial<T>
, die Ihnen dies ermöglicht....
class Person {
public name: string = "default"
public address: string = "default"
public age: number = 0;
public constructor(init?:Partial<Person>) {
Object.assign(this, init);
}
}
let persons = [
new Person(),
new Person({}),
new Person({name:"John"}),
new Person({address:"Earth"}),
new Person({age:20, address:"Earth", name:"John"}),
];
Ursprüngliche Antwort:
Mein Ansatz ist die Definition einer separaten fields
Variable, die Sie an den Konstruktor übergeben. Der Trick besteht darin, alle Klassenfelder für diesen Initialisierer als optional umzudefinieren. Wenn das Objekt (mit seinen Standardwerten) erstellt ist, weisen Sie das Initialisierungsobjekt einfach der Variablen this
;
export class Person {
public name: string = "default"
public address: string = "default"
public age: number = 0;
public constructor(
fields?: {
name?: string,
address?: string,
age?: number
}) {
if (fields) Object.assign(this, fields);
}
}
oder machen Sie es manuell (etwas sicherer):
if (fields) {
this.name = fields.name || this.name;
this.address = fields.address || this.address;
this.age = fields.age || this.age;
}
Verwendung:
let persons = [
new Person(),
new Person({name:"Joe"}),
new Person({
name:"Joe",
address:"planet Earth"
}),
new Person({
age:5,
address:"planet Earth",
name:"Joe"
}),
new Person(new Person({name:"Joe"})) //shallow clone
];
und Konsolenausgaben:
Person { name: 'default', address: 'default', age: 0 }
Person { name: 'Joe', address: 'default', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 0 }
Person { name: 'Joe', address: 'planet Earth', age: 5 }
Person { name: 'Joe', address: 'default', age: 0 }
Dies gibt Ihnen grundlegende Sicherheit und Eigenschaftsinitialisierung, aber es ist alles optional und kann außer der Reihe sein. Sie erhalten die Standardwerte der Klasse, wenn Sie kein Feld übergeben.
Sie können es auch mit erforderlichen Konstruktorparametern mischen - bleiben Sie bei fields
am Ende.
So nah am C#-Stil wie möglich, denke ich ( die eigentliche field-init-Syntax wurde abgelehnt ). Ich würde einen richtigen Feldinitialisierer bevorzugen, aber es sieht nicht so aus, als würde das noch passieren.
Zum Vergleich: Wenn Sie den Casting-Ansatz verwenden, muss Ihr Initialisierungsobjekt über ALLE Felder des Typs verfügen, auf den Sie casten, und Sie erhalten keine klassenspezifischen Funktionen (oder Ableitungen), die von der Klasse selbst erstellt wurden.
Seit ich diese Antwort geschrieben habe, haben sich bessere Möglichkeiten ergeben. Bitte beachten Sie die anderen Antworten unten, die mehr Stimmen und eine bessere Antwort haben. Ich kann diese Antwort nicht entfernen, da sie als akzeptiert markiert ist.
Es gibt ein Problem auf dem TypeScript-Codeplex, das dies beschreibt: Unterstützung für Objektinitialisierer .
Wie bereits erwähnt, können Sie dies bereits tun, indem Sie in TypeScript Schnittstellen anstelle von Klassen verwenden:
interface Name {
givenName: string;
surname: string;
}
class Person {
name: Name;
age: number;
}
var bob: Person = {
name: {
givenName: "Bob",
surname: "Smith",
},
age: 35,
};
Im Folgenden wird eine Lösung vorgestellt, die eine kürzere Anwendung von Object.assign
um dem Original näher zu kommen C#
Muster.
Doch zunächst ein Überblick über die bisher angebotenen Techniken, die da wären
Object.assign
Partial<T>
Trick innerhalb des KopierkonstruktorsObject.create
anstelle von Object.assign
Natürlich haben beide ihre Vor- und Nachteile. Das Ändern einer Zielklasse, um einen Kopierkonstruktor zu erstellen, ist nicht immer eine Option. Und beim "Casting" gehen alle mit dem Zieltyp verbundenen Funktionen verloren. Object.create
scheint weniger attraktiv zu sein, da es eine ziemlich ausführliche Eigenschaftsbeschreibung erfordert.
Hier ist also ein weiterer Ansatz, der etwas einfacher ist, die Typdefinition und die zugehörigen Funktionsprototypen beibehält und die beabsichtigte Methode besser abbildet C#
Muster:
const john = Object.assign( new Person(), {
name: "John",
age: 29,
address: "Earth"
});
Das war's. Der einzige Zusatz gegenüber dem C#
Muster ist Object.assign
zusammen mit 2 Klammern und einem Komma. Überprüfen Sie anhand des folgenden Arbeitsbeispiels, ob die Funktionsprototypen des Typs erhalten bleiben. Es sind keine Konstruktoren und keine cleveren Tricks erforderlich.
Dieses Beispiel zeigt, wie man ein Objekt mit einer Annäherung an eine C#
Feldinitialisierer:
class Person {
name: string = '';
address: string = '';
age: number = 0;
aboutMe() {
return `Hi, I'm ${this.name}, aged ${this.age} and from ${this.address}`;
}
}
// typescript field initializer (maintains "type" definition)
const john = Object.assign( new Person(), {
name: "John",
age: 29,
address: "Earth"
});
// initialized object maintains aboutMe() function prototype
console.log( john.aboutMe() );
Sie können ein anonymes Objekt beeinflussen, das in Ihren Klassentyp gecastet wurde. Bonus : In Visual Studio, profitieren Sie von intellisense auf diese Weise :)
var anInstance: AClass = <AClass> {
Property1: "Value",
Property2: "Value",
PropertyBoolean: true,
PropertyNumber: 1
};
Bearbeiten:
WARNUNG Wenn die Klasse Methoden hat, wird die Instanz Ihrer Klasse diese nicht erhalten. Wenn AClass einen Konstruktor hat, wird dieser nicht ausgeführt. Wenn Sie instanceof AClass verwenden, erhalten Sie false.
Zusammenfassend lässt sich sagen, dass Sie eine Schnittstelle und keine Klasse verwenden sollten. . Am häufigsten wird das Domänenmodell als "Plain Old Objects" deklariert. In der Tat sollten Sie für ein Domänenmodell besser eine Schnittstelle statt einer Klasse verwenden. Schnittstellen werden zur Kompilierungszeit für die Typüberprüfung verwendet und im Gegensatz zu Klassen werden Schnittstellen während der Kompilierung vollständig entfernt.
interface IModel {
Property1: string;
Property2: string;
PropertyBoolean: boolean;
PropertyNumber: number;
}
var anObject: IModel = {
Property1: "Value",
Property2: "Value",
PropertyBoolean: true,
PropertyNumber: 1
};
Ich schlage einen Ansatz vor, der kein Typescript 2.1 erfordert:
class Person {
public name: string;
public address?: string;
public age: number;
public constructor(init:Person) {
Object.assign(this, init);
}
public someFunc() {
// todo
}
}
let person = new Person(<Person>{ age:20, name:"John" });
person.someFunc();
wichtige Punkte:
Partial<T>
nicht erforderlich 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.