Come posso creare un oggetto basato sulla definizione di un file di interfaccia in TypeScript?


313

Ho definito un'interfaccia come questa:

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

Definisco una variabile come questa:

var modal: IModal;

Tuttavia, quando provo a impostare la proprietà modale mi dà un messaggio che dice che

"cannot set property content of undefined"

Va bene usare un'interfaccia per descrivere il mio oggetto modale e se sì, come dovrei crearlo?

Risposte:


426

Se stai creando la variabile "modale" altrove e vuoi dire a TypeScript che sarà fatto tutto, useresti:

declare const modal: IModal;

Se si desidera creare una variabile che sarà effettivamente un'istanza di IModal in TypeScript, è necessario definirla completamente.

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

O menzogna, con un'asserzione di tipo, ma perderai la sicurezza del tipo in quanto ora non sarai definito in luoghi inaspettati, e possibilmente errori di runtime, quando accedi modal.contente così via (proprietà che il contratto dice saranno lì).

const modal = {} as IModal;

Classe di esempio

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

const modal = new Modal();

Potresti pensare "hey è davvero una duplicazione dell'interfaccia" - e hai ragione. Se la classe Modale è l'unica implementazione dell'interfaccia IModal, potresti voler eliminare del tutto l'interfaccia e utilizzare ...

const modal: Modal = new Modal();

Piuttosto che

const modal: IModal = new Modal();

2
Grazie. Speravo di evitare di dover definire inizialmente tutti i contenuti modali. Sarebbe più semplice se al posto di un'interfaccia definissi Modale come una classe con proprietà e poi usassi new e un costruttore per impostare tutti i valori iniziali?

1
Sì, potresti definire una classe e quindi dovrai creare nuove istanze solo quando ne hai bisogno. Ti serve un esempio?
Fenton,

2
Ho aggiunto un esempio e una nota sull'interfaccia.
Fenton,

21
var modal = <IModal>{};questo è quello che stavo cercando ;-) grazie!
Legends

5
Cordiali saluti, è meglio usare {} as IModalpiuttosto che <IModal>{}. Rimuove un'ambiguità nella grammatica della lingua quando si usano <foo>asserzioni di stile in JSX. Per saperne di più . E, naturalmente, utilizzare leto constinvece di var.
Alex Klaus,

191

Se vuoi un oggetto vuoto di un'interfaccia, puoi fare solo:

var modal = <IModal>{};

Il vantaggio dell'uso delle interfacce al posto delle classi per strutturare i dati è che se non si hanno metodi sulla classe, questo verrà mostrato in JS compilato come metodo vuoto. Esempio:

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

compila in

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

che non ha valore. Le interfacce, d'altra parte, non si presentano affatto in JS, fornendo comunque i vantaggi della strutturazione dei dati e del controllo del tipo.


1
`Per aggiungere al commento sopra. Per chiamare una funzione "updateModal (IModal modalInstance) {}", puoi creare un'istanza inline dell'interfaccia 'IModal', come questa: // un codice qui, dove sono accessibili la funzione updateModal e IModal: updateModal (<IModal> {// questa riga crea un contenuto di istanza: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submit: null}); // completa il tuo codice `
Sunny

usando var modal= <abc>{}abbiamo appena assegnato modale di tipo abc di oggetto vuoto ma dove abbiamo dichiarato il tipo di modale? sto usando typescript6.
Pardeep Jain,

Questo non ha funzionato per me, ho dovuto inizializzare l'intero oggetto come indicato nella risposta accettata.
Rahul Sonwanshi,


22

Penso che tu abbia sostanzialmente cinque diverse opzioni per farlo. Scegliere tra loro potrebbe essere facile a seconda dell'obiettivo che vorresti raggiungere.

Il modo migliore nella maggior parte dei casi per usare una classe e crearne un'istanza , poiché stai usando TypeScript per applicare il controllo del tipo.

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

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

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

    foo(param: string): void {
    }
}

Anche se altri metodi offrono modi più semplici per creare un oggetto da un'interfaccia, dovresti considerare di dividere la tua interfaccia a parte, se stai usando il tuo oggetto per questioni diverse e non causa la sovra-segregazione dell'interfaccia:

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

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

D'altra parte, ad esempio durante il test dell'unità del codice (se non si può applicare frequentemente la separazione delle preoccupazioni), si potrebbe essere in grado di accettare gli svantaggi per motivi di produttività. Puoi applicare altri metodi per creare simulazioni principalmente per interfacce di terze parti * .d.ts. E potrebbe essere una seccatura implementare sempre oggetti completamente anonimi per ogni enorme interfaccia.

In questo percorso la prima opzione è creare un oggetto vuoto :

 var modal = <IModal>{};

In secondo luogo, realizzare pienamente la parte obbligatoria della tua interfaccia . Può essere utile se stai chiamando librerie JavaScript di terze parti, ma penso che dovresti invece creare una classe, come prima:

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

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

In terzo luogo puoi creare solo una parte della tua interfaccia e creare un oggetto anonimo , ma in questo modo sei responsabile di adempiere al contratto

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

    }
};

Riassumendo la mia risposta anche se le interfacce sono opzionali, poiché non sono traspilettate in codice JavaScript, TypeScript è lì per fornire un nuovo livello di astrazione, se usato con saggezza e coerenza. Penso, solo perché puoi scartarli nella maggior parte dei casi dal tuo codice, non dovresti.



12

Dal momento che non ho trovato una risposta uguale nella parte superiore e la mia risposta è diversa. Lo voglio:

modal: IModal = <IModal>{}

2

Usando la tua interfaccia puoi farlo

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

Ecco un altro approccio:

Puoi semplicemente creare un oggetto compatibile con ESLint come questo

const modal: IModal = {} as IModal;

O un'istanza predefinita basata sull'interfaccia e con valori predefiniti sensibili, se presenti

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

Quindi variazioni dell'istanza predefinita semplicemente sostituendo alcune proprietà

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

1

Molte delle soluzioni finora pubblicate utilizzano asserzioni di tipo e quindi non generano errori di compilazione se nell'implementazione vengono omesse le proprietà dell'interfaccia richieste.

Per coloro che sono interessati ad altre soluzioni robuste e compatte :

Opzione 1: creare un'istanza di una classe anonima che implementa l'interfaccia:

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

Opzione 2: creare una funzione di utilità:

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

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

0

È possibile impostare i valori predefiniti utilizzando Class.

Senza costruttore di 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}

Con costruttore di classe

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}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.