Jak mogę utworzyć obiekt na podstawie definicji pliku interfejsu w TypeScript?


313

Zdefiniowałem taki interfejs:

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

Definiuję zmienną taką jak ta:

var modal: IModal;

Kiedy jednak próbuję ustawić właściwość modalu, pojawia się komunikat, że to mówi

"cannot set property content of undefined"

Czy można używać interfejsu do opisywania mojego obiektu modalnego, a jeśli tak, to jak go utworzyć?

Odpowiedzi:


426

Jeśli tworzysz zmienną „modalną” gdzie indziej i chcesz powiedzieć TypeScript, że wszystko się skończy, użyjesz:

declare const modal: IModal;

Jeśli chcesz utworzyć zmienną, która faktycznie będzie instancją IModal w TypeScript, musisz ją w pełni zdefiniować.

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

Lub kłam, z twierdzeniem typu, ale stracisz bezpieczeństwo typu, ponieważ będziesz teraz niezdefiniowany w nieoczekiwanych miejscach i możliwe błędy w czasie wykonywania, podczas uzyskiwania dostępu modal.contenti tak dalej (właściwości, które według umowy będą dostępne).

const modal = {} as IModal;

Przykładowa klasa

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

const modal = new Modal();

Możesz pomyśleć „hej, to naprawdę duplikacja interfejsu” - i masz rację. Jeśli klasa Modal jest jedyną implementacją interfejsu IModal, możesz chcieć całkowicie usunąć interfejs i użyć ...

const modal: Modal = new Modal();

Zamiast

const modal: IModal = new Modal();

2
Dzięki. Miałem nadzieję, że uniknę na początku definiowania całej zawartości modalnej. Czy byłoby łatwiej, gdyby zamiast interfejsu zdefiniowałem Modal jako klasę z właściwościami, a następnie użyłem new i konstruktora do ustawienia wszystkich wartości początkowych?

1
Tak - możesz zdefiniować klasę, a wtedy będziesz musiał tworzyć nowe wystąpienia tylko wtedy, gdy ich potrzebujesz. Potrzebujesz przykładu?
Fenton

2
Dodałem przykład i notatkę na temat interfejsu.
Fenton

21
var modal = <IModal>{};tego właśnie szukałem ;-) dzięki!
Legendy,

5
Do twojej wiadomości, lepiej jest użyć {} as IModalniż <IModal>{}. Usuwa niejednoznaczność w gramatyce języka podczas używania <foo>asercji stylu w JSX. Czytaj dalej . I oczywiście użyj letlub constzamiast var.
Alex Klaus

191

Jeśli chcesz pusty obiekt interfejsu, możesz po prostu:

var modal = <IModal>{};

Zaletą używania interfejsów zamiast klas do strukturyzacji danych jest to, że jeśli nie masz żadnych metod w klasie, będzie ona wyświetlana w skompilowanym JS jako pusta metoda. Przykład:

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

kompiluje się w

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

który nie ma żadnej wartości. Z drugiej strony interfejsy w ogóle nie pojawiają się w JS, a jednocześnie zapewniają zalety strukturyzacji danych i sprawdzania typów.


1
`Aby dodać do powyższego komentarza. Aby wywołać funkcję „updateModal (IModal modalInstance) {}”, możesz utworzyć wbudowaną instancję interfejsu „IModal”, w ten sposób: // jakiś kod tutaj, gdzie dostępna jest funkcja updateModal i IModal: updateModal (<IModal> {// ten wiersz tworzy treść instancji: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // uzupełnij kod `
Sunny

za pomocą var modal= <abc>{}właśnie przypisaliśmy modal typu abc pustego obiektu, ale gdzie zadeklarowaliśmy typ modalu? Używam maszynopisu 6.
Pardeep Jain

To nie zadziałało. Musiałem zainicjować cały obiekt, jak podano w zaakceptowanej odpowiedzi.
Rahul Sonwanshi


22

Myślę, że masz w zasadzie pięć różnych opcji . Wybór spośród nich może być łatwy w zależności od celu, który chcesz osiągnąć.

W większości przypadków najlepszym sposobem jest użycie klasy i utworzenie jej instancji , ponieważ do sprawdzania typu używasz TypeScript.

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

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

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

    foo(param: string): void {
    }
}

Nawet jeśli inne metody oferują łatwiejsze sposoby tworzenia obiektu z interfejsu, powinieneś rozważyć podzielenie interfejsu na siebie, jeśli używasz swojego obiektu do różnych spraw i nie powoduje to nadmiernej segregacji interfejsu:

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

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

Z drugiej strony, na przykład podczas testowania jednostkowego kodu (jeśli często nie stosujesz separacji problemów), możesz zaakceptować wady ze względu na produktywność. Możesz zastosować inne metody tworzenia makiet głównie dla dużych interfejsów * .d.ts innych firm. I zawsze może być problem z implementacją w pełni anonimowych obiektów dla każdego ogromnego interfejsu.

Na tej ścieżce pierwszą opcją jest utworzenie pustego obiektu :

 var modal = <IModal>{};

Po drugie, aby w pełni zrealizować obowiązkową część interfejsu . Może to być przydatne, niezależnie od tego, czy wywołujesz biblioteki JavaScript innych firm, ale myślę, że powinieneś utworzyć klasę, tak jak wcześniej:

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

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

Po trzecie, możesz stworzyć tylko część swojego interfejsu i stworzyć anonimowy obiekt , ale w ten sposób jesteś odpowiedzialny za wykonanie umowy

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

    }
};

Podsumowując moją odpowiedź, nawet jeśli interfejsy są opcjonalne, ponieważ nie są transponowane do kodu JavaScript, TypeScript zapewnia nowy poziom abstrakcji, jeśli jest używany mądrze i konsekwentnie. Myślę, że tylko dlatego, że możesz usunąć je w większości przypadków z własnego kodu, nie powinieneś.



12

Ponieważ nie znalazłem równej odpowiedzi na górze, a moja odpowiedź jest inna. Ja robię:

modal: IModal = <IModal>{}

2

Za pomocą interfejsu możesz to zrobić

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

Oto inne podejście:

Możesz po prostu utworzyć taki przyjazny obiekt ESLint

const modal: IModal = {} as IModal;

Lub instancja domyślna oparta na interfejsie i z rozsądnymi ustawieniami domyślnymi, jeśli takie istnieją

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

Następnie odmiany domyślnego wystąpienia po prostu przesłaniając niektóre właściwości

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

1

Wiele z dotychczas opublikowanych rozwiązań używa asercji typu i dlatego nie zgłaszają błędów kompilacji, jeśli wymagane właściwości interfejsu zostaną pominięte w implementacji.

Dla osób zainteresowanych innymi solidnymi, kompaktowymi rozwiązaniami :

Opcja 1: Utwórz anonimową klasę, która implementuje interfejs:

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

Opcja 2: Utwórz funkcję narzędzia:

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

impl<MyInterface>({
  nameFirst: 'John';
  nameFamily: 'Smith';
})
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.