Wie kann ich ein Objekt basierend auf einer Schnittstellendateidefinition in TypeScript erstellen?


313

Ich habe eine Schnittstelle wie diese definiert:

interface IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
 }

Ich definiere eine Variable wie folgt:

var modal: IModal;

Wenn ich jedoch versuche, die Eigenschaft von modal festzulegen, wird eine Meldung angezeigt, die dies besagt

"cannot set property content of undefined"

Ist es in Ordnung, eine Schnittstelle zur Beschreibung meines modalen Objekts zu verwenden, und wenn ja, wie soll ich es erstellen?

Antworten:


426

Wenn Sie die "modale" Variable an anderer Stelle erstellen und TypeScript mitteilen möchten, dass alles erledigt ist, verwenden Sie Folgendes:

declare const modal: IModal;

Wenn Sie eine Variable erstellen möchten, die tatsächlich eine Instanz von IModal in TypeScript ist, müssen Sie sie vollständig definieren.

const modal: IModal = {
    content: '',
    form: '',
    href: '',
    $form: null,
    $message: null,
    $modal: null,
    $submits: null
};

Oder lügen Sie mit einer Typzusicherung, aber Sie verlieren die Typensicherheit, da Sie jetzt an unerwarteten Stellen und möglicherweise Laufzeitfehlern beim Zugriff modal.contentusw. undefiniert werden (Eigenschaften, die laut Vertrag vorhanden sind).

const modal = {} as IModal;

Beispielklasse

class Modal implements IModal {
    content: string;
    form: string;
    href: string;
    $form: JQuery;
    $message: JQuery;
    $modal: JQuery;
    $submits: JQuery;
}

const modal = new Modal();

Sie denken vielleicht "Hey, das ist wirklich eine Verdoppelung der Schnittstelle" - und Sie haben Recht. Wenn die Modal-Klasse die einzige Implementierung der IModal-Schnittstelle ist, möchten Sie möglicherweise die Schnittstelle vollständig löschen und ...

const modal: Modal = new Modal();

Eher, als

const modal: IModal = new Modal();

2
Vielen Dank. Ich hatte gehofft, zunächst nicht alle modalen Inhalte definieren zu müssen. Wäre es einfacher, wenn ich anstelle einer Schnittstelle Modal als Klasse mit Eigenschaften definieren und dann new und einen Konstruktor verwenden würde, um alle Anfangswerte einzurichten?

1
Ja - Sie könnten eine Klasse definieren und müssten dann nur dann neue Instanzen erstellen, wenn Sie sie benötigen. Benötigen Sie ein Beispiel?
Fenton

2
Ich habe ein Beispiel und einen Hinweis zur Benutzeroberfläche hinzugefügt.
Fenton

21
var modal = <IModal>{};das habe ich gesucht ;-) danke!
Legenden

5
Zu Ihrer Information, es ist besser zu verwenden {} as IModalals <IModal>{}. Es beseitigt eine Mehrdeutigkeit in der Sprachgrammatik, wenn <foo>Stilzusicherungen in JSX verwendet werden. Lesen Sie mehr . Und natürlich verwenden letoder constanstelle von var.
Alex Klaus

191

Wenn Sie ein leeres Objekt einer Schnittstelle möchten, können Sie Folgendes tun:

var modal = <IModal>{};

Der Vorteil der Verwendung von Schnittstellen anstelle von Klassen zum Strukturieren von Daten besteht darin, dass wenn Sie keine Methoden für die Klasse haben, diese in kompiliertem JS als leere Methode angezeigt werden. Beispiel:

class TestClass {
    a: number;
    b: string;
    c: boolean;
}

kompiliert in

var TestClass = (function () {
    function TestClass() {
    }
    return TestClass;
})();

das trägt keinen Wert. Schnittstellen hingegen werden in JS überhaupt nicht angezeigt und bieten dennoch die Vorteile der Datenstrukturierung und Typprüfung.


1
`Zum obigen Kommentar hinzufügen. Um eine Funktion "updateModal (IModal modalInstance) {}" aufzurufen, können Sie eine Inline-Instanz der Schnittstelle 'IModal' erstellen, z {// Diese Zeile erstellt einen Instanzinhalt: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // Vervollständige deinen Code `
Sunny

Durch die Verwendung haben var modal= <abc>{}wir nur Modal vom Typ abc des leeren Objekts zugewiesen, aber wo haben wir den Modaltyp deklariert? Ich benutze Typoskript6.
Pardeep Jain

Dies funktionierte bei mir nicht. Ich musste das gesamte Objekt wie in der akzeptierten Antwort angegeben initialisieren.
Rahul Sonwanshi


22

Ich denke, Sie haben grundsätzlich fünf verschiedene Möglichkeiten , dies zu tun. Die Auswahl unter ihnen kann je nach dem Ziel, das Sie erreichen möchten, einfach sein.

In den meisten Fällen ist es am besten, eine Klasse zu verwenden und zu instanziieren , da Sie TypeScript verwenden, um die Typprüfung anzuwenden.

interface IModal {
    content: string;
    form: string;
    //...

    //Extra
    foo: (bar: string): void;
}

class Modal implements IModal {
    content: string;
    form: string;

    foo(param: string): void {
    }
}

Selbst wenn andere Methoden einfachere Möglichkeiten zum Erstellen eines Objekts aus einer Schnittstelle bieten, sollten Sie in Betracht ziehen , Ihre Schnittstelle aufzuteilen, wenn Sie Ihr Objekt für verschiedene Zwecke verwenden und dies keine Übersegregation der Schnittstelle verursacht:

interface IBehaviour {
    //Extra
    foo(param: string): void;
}

interface IModal extends IBehaviour{
    content: string;
    form: string;
    //...
}

Auf der anderen Seite können Sie beispielsweise beim Testen Ihres Codes in Einheiten (wenn Sie die Trennung von Bedenken nicht häufig anwenden) die Nachteile möglicherweise aus Gründen der Produktivität akzeptieren. Sie können andere Methoden anwenden, um Mocks zu erstellen, hauptsächlich für große * .d.ts-Schnittstellen von Drittanbietern. Und es könnte schwierig sein, immer vollständige anonyme Objekte für jede große Schnittstelle zu implementieren.

Auf diesem Pfad können Sie zunächst ein leeres Objekt erstellen :

 var modal = <IModal>{};

Zweitens, um den obligatorischen Teil Ihrer Benutzeroberfläche vollständig zu realisieren . Es kann nützlich sein, ob Sie JavaScript-Bibliotheken von Drittanbietern aufrufen, aber ich denke, Sie sollten stattdessen wie zuvor eine Klasse erstellen:

var modal: IModal = {
    content: '',
    form: '',
    //...

    foo: (param: string): void => {
    }
};

Drittens können Sie nur einen Teil Ihrer Benutzeroberfläche erstellen und ein anonymes Objekt erstellen. Auf diese Weise sind Sie jedoch für die Erfüllung des Vertrags verantwortlich

var modal: IModal = <any>{
    foo: (param: string): void => {

    }
};

Zusammenfassend lässt sich sagen, dass TypeScript eine neue Abstraktionsebene bietet, wenn es sinnvoll und konsistent verwendet wird, auch wenn Schnittstellen optional sind, da sie nicht in JavaScript-Code transpiliert sind. Ich denke, nur weil Sie sie in den meisten Fällen aus Ihrem eigenen Code entfernen können, sollten Sie es nicht tun.



12

Da ich oben keine gleiche Antwort gefunden habe und meine Antwort anders ist. Ich mache:

modal: IModal = <IModal>{}

2

Mit Ihrer Schnittstelle können Sie tun

class Modal() {
  constructor(public iModal: IModal) {
   //You now have access to all your interface variables using this.iModal object,
   //you don't need to define the properties at all, constructor does it for you.
  }
}

2

Hier ist ein anderer Ansatz:

Sie können einfach ein ESLint-freundliches Objekt wie dieses erstellen

const modal: IModal = {} as IModal;

Oder eine Standardinstanz, die auf der Schnittstelle basiert und gegebenenfalls sinnvolle Standardeinstellungen aufweist

const defaultModal: IModal = {
    content: "",
    form: "",
    href: "",
    $form: {} as JQuery,
    $message: {} as JQuery,
    $modal: {} as JQuery,
    $submits: {} as JQuery
};

Dann Variationen der Standardinstanz, indem einfach einige Eigenschaften überschrieben werden

const confirmationModal: IModal = {
    ...defaultModal,     // all properties/values from defaultModal
    form: "confirmForm"  // override form only
}

1

Viele der bisher veröffentlichten Lösungen verwenden Typzusicherungen und werfen daher keine Kompilierungsfehler aus, wenn die erforderlichen Schnittstelleneigenschaften in der Implementierung weggelassen werden.

Für diejenigen, die an anderen robusten, kompakten Lösungen interessiert sind :

Option 1: Instanziieren Sie eine anonyme Klasse, die die Schnittstelle implementiert:

new class implements MyInterface {
  nameFirst = 'John';
  nameFamily = 'Smith';
}();

Option 2: Erstellen Sie eine Dienstprogrammfunktion:

export function impl<I>(i: I) { return i; }

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})

0

Sie können Standardwerte mit festlegen Class.

Ohne Klassenkonstruktor:

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
};

class Modal implements IModal {
  content = "";
  form = "";
  href: string;  // will not be added to object
  isPopup = true;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}

Mit Klassenkonstruktor

interface IModal {
  content: string;
  form: string;
  href: string;
  isPopup: boolean;
}

class Modal implements IModal {
  constructor() {
    this.content = "";
    this.form = "";
    this.isPopup = true;
  }

  content: string;

  form: string;

  href: string; // not part of constructor so will not be added to object

  isPopup: boolean;
}

const myModal = new Modal();
console.log(myModal); // output: {content: "", form: "", isPopup: true}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.