Comment puis-je créer un objet basé sur une définition de fichier d'interface dans TypeScript?

313

J'ai défini une interface comme celle-ci:

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

Je définis une variable comme celle-ci:

var modal: IModal;

Cependant, lorsque j'essaie de définir la propriété de modal, cela me donne un message disant que

"cannot set property content of undefined"

Est-il correct d'utiliser une interface pour décrire mon objet modal et si oui, comment dois-je le créer?

Trilarion
la source

Réponses:

426

Si vous créez la variable "modale" ailleurs et que vous voulez dire à TypeScript que tout sera fait, vous utiliserez:

declare const modal: IModal;

Si vous souhaitez créer une variable qui sera en fait une instance d'IModal dans TypeScript, vous devrez la définir entièrement.

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

Ou mentir, avec une assertion de type, mais vous perdrez la sécurité du type car vous serez désormais indéfini dans des endroits inattendus, et éventuellement des erreurs d'exécution, lors de l'accès modal.contentet ainsi de suite (les propriétés qui, selon le contrat, seront là).

const modal = {} as IModal;

Exemple de classe

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

const modal = new Modal();

Vous pouvez penser "hé c'est vraiment une duplication de l'interface" - et vous avez raison. Si la classe Modal est la seule implémentation de l'interface IModal, vous pouvez supprimer complètement l'interface et utiliser ...

const modal: Modal = new Modal();

Plutôt que

const modal: IModal = new Modal();
Fenton
la source
2
Merci. J'espérais éviter d'avoir à définir tout le contenu modal au départ. Serait-il plus facile si au lieu d'une interface, je définissais Modal comme une classe avec des propriétés et utilisais ensuite new et un constructeur pour configurer toutes les valeurs initiales?
1
Oui - vous pouvez définir une classe et vous ne devrez créer de nouvelles instances que lorsque vous en aurez besoin. Avez-vous besoin d'un exemple?
Fenton
2
J'ai ajouté un exemple et une note sur l'interface.
Fenton
21
var modal = <IModal>{};c'est ce que je cherchais ;-) merci!
Legends
5
Pour info, il vaut mieux utiliser {} as IModalplutôt que <IModal>{}. Il supprime une ambiguïté dans la grammaire du langage lors de l'utilisation d' <foo>assertions de style dans JSX. Lisez plus . Et bien sûr, utilisez letou constau lieu de var.
Alex Klaus
191

Si vous voulez un objet vide d'une interface, vous pouvez faire simplement:

var modal = <IModal>{};

L'avantage d'utiliser des interfaces à la place des classes pour structurer les données est que si vous n'avez aucune méthode sur la classe, elle s'affichera dans JS compilé comme une méthode vide. Exemple:

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

compile en

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

qui n'a aucune valeur. Les interfaces, en revanche, n'apparaissent pas du tout dans JS tout en offrant les avantages de la structuration des données et de la vérification de type.

user3180970
la source
1
`Pour ajouter au commentaire ci-dessus. Pour appeler une fonction "updateModal (IModal modalInstance) {}", vous pouvez créer une instance en ligne de l'interface 'IModal', comme ceci: // du code ici, où la fonction updateModal et IModal sont accessibles: updateModal (<IModal> {// cette ligne crée un contenu d'instance: '', formulaire: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // Complétez votre code `
Sunny
en utilisant var modal= <abc>{}nous avons juste assigné un modal de type abc d'objet vide mais où avons-nous déclaré un type de modal? j'utilise typescript6.
Pardeep Jain
Cela n'a pas fonctionné pour moi, j'ai dû initialiser tout l'objet comme indiqué dans la réponse acceptée.
Rahul Sonwanshi
22

Je pense que vous avez essentiellement cinq options différentes pour le faire. Choisir parmi eux pourrait être facile selon l'objectif que vous souhaitez atteindre.

La meilleure façon dans la plupart des cas d' utiliser une classe et de l'instancier , car vous utilisez TypeScript pour appliquer la vérification de type.

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

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

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

    foo(param: string): void {
    }
}

Même si d'autres méthodes offrent des moyens plus faciles de créer un objet à partir d'une interface, vous devriez envisager de séparer votre interface , si vous utilisez votre objet pour différentes questions, et cela ne provoque pas une surségrégation d'interface:

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

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

D'un autre côté, par exemple lors des tests unitaires de votre code (si vous n'appliquez pas fréquemment la séparation des problèmes), vous pouvez être en mesure d'accepter les inconvénients pour des raisons de productivité. Vous pouvez appliquer d'autres méthodes pour créer des simulations principalement pour les grandes interfaces tierces * .d.ts. Et il pourrait être difficile de toujours implémenter des objets anonymes complets pour chaque énorme interface.

Sur ce chemin, votre première option est de créer un objet vide :

 var modal = <IModal>{};

Deuxièmement, pour réaliser pleinement la partie obligatoire de votre interface . Il peut être utile que vous appeliez des bibliothèques JavaScript tierces, mais je pense que vous devriez plutôt créer une classe, comme avant:

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

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

Troisièmement, vous pouvez créer juste une partie de votre interface et créer un objet anonyme , mais de cette façon, vous êtes responsable de l'exécution du contrat

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

    }
};

Résumant ma réponse même si les interfaces sont facultatives, car elles ne sont pas transposées en code JavaScript, TypeScript est là pour fournir un nouveau niveau d'abstraction, s'il est utilisé avec sagesse et cohérence. Je pense que ce n'est pas parce que vous pouvez les rejeter dans la plupart des cas de votre propre code.

Ursegor
la source
18

Tu peux faire

var modal = {} as IModal 
Kangudie Muanza - Killmonger
la source
12

Puisque je n'ai pas trouvé de réponse égale en haut et ma réponse est différente. Je fais:

modal: IModal = <IModal>{}
Zokor
la source
2

En utilisant votre interface, vous pouvez faire

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.
  }
}
Byrd
la source
2

Voici une autre approche:

Vous pouvez simplement créer un objet convivial ESLint comme celui-ci

const modal: IModal = {} as IModal;

Ou une instance par défaut basée sur l'interface et avec des valeurs par défaut sensibles, le cas échéant

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

Ensuite, des variations de l'instance par défaut simplement en remplaçant certaines propriétés

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

De nombreuses solutions publiées jusqu'à présent utilisent des assertions de type et ne génèrent donc pas d'erreurs de compilation si les propriétés d'interface requises sont omises dans l'implémentation.

Pour ceux intéressés par d'autres solutions robustes et compactes :

Option 1: instancier une classe anonyme qui implémente l'interface:

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

Option 2: créer une fonction utilitaire:

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

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})
Stephen Paul
la source
0

Vous pouvez définir des valeurs par défaut à l'aide de Class.

Sans constructeur de classe:

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}

Avec Class Constructor

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}
JerryGoyal
la source