Как создать объект на основе определения файла интерфейса в TypeScript?

Я определил интерфейс как это:

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

Я определяю переменную следующим образом:

var modal: IModal;

Тем не менее, когда я пытаюсь установить свойство модальной, я получаю сообщение о том, что

"cannot set property content of undefined"

Можно ли использовать интерфейс для описания моего модального объекта, и если да, то как мне его создать?

Ответ 1

Если вы создаете "модальную" переменную в другом месте и хотите сообщить TypeScript, что все это будет сделано, вы должны использовать:

declare const modal: IModal;

Если вы хотите создать переменную, которая на самом деле будет экземпляром IModal в TypeScript, вам нужно будет определить ее полностью.

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

Или ложь с утверждением типа, но вы потеряете безопасность типов, поскольку теперь вы будете получать неопределенные значения в неожиданных местах и, возможно, во время выполнения при доступе к modal.content и т.д. (Свойства, которые, согласно контракту, будут там).

const modal = {} as IModal;

Пример класса

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

const modal = new Modal();

Вы можете подумать "эй, что на самом деле дублирование интерфейса" - и вы правы. Если класс Modal является единственной реализацией интерфейса IModal, вы можете вообще удалить интерфейс и использовать...

const modal: Modal = new Modal();

Скорее, чем

const modal: IModal = new Modal();

Ответ 2

Если вам нужен пустой объект интерфейса, вы можете сделать только:

var modal = <IModal>{};

Преимущество использования интерфейсов вместо классов для структурирования данных заключается в том, что, если у вас нет каких-либо методов в классе, он будет отображаться в скомпилированном JS как пустой метод. Пример:

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

компилируется в

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

который не имеет значения. С другой стороны, интерфейсы вообще не отображаются в JS, сохраняя при этом преимущества структурирования данных и проверки типов.

Ответ 3

Если вы используете React, синтаксический анализатор будет подавлять традиционный синтаксис, поэтому была использована альтернатива для использования в файлах .tsx.

let a = {} as MyInterface;

https://www.typescriptlang.org/docs/handbook/jsx.html

Ответ 4

Я думаю, что у вас есть в основном пять различных опций. Выбор среди них может быть легким в зависимости от цели, которую вы хотели бы достичь.

Лучший способ в большинстве случаев использовать использовать класс и создавать его, потому что вы используете TypeScript для применения проверки типов.

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

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

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

    foo(param: string): void {
    }
}

Даже если другие методы предлагают более простые способы создания объекта из интерфейса, вы должны рассмотреть раздел разделение вашего интерфейса, если вы используете свой объект по разным вопросам, и это не вызывает -сегрегация:

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

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

С другой стороны, например, во время модульного тестирования вашего кода (если вы не можете часто применять разделение проблем), вы можете принять недостатки ради производительности. Вы можете применять другие методы для создания mocks в основном для больших сторонних интерфейсов *.d.ts. И может быть больно всегда реализовывать полные анонимные объекты для каждого огромного интерфейса.

На этом пути ваш первый вариант - создать пустой объект:

 var modal = <IModal>{};

Во-вторых, полностью реализовать обязательную часть вашего интерфейса. Это может быть полезно, если вы вызываете сторонние библиотеки JavaScript, но я думаю, что вы должны создать класс, а не раньше:

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

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

В-третьих, вы можете создать только часть вашего интерфейса и создать анонимный объект , но таким образом вы несете ответственность за выполнение контракта

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

    }
};

Подводя итог моему ответу, даже если интерфейсы являются необязательными, потому что они не передаются в код JavaScript, TypeScript должен предоставить новый уровень абстракции, если использовать его мудро и последовательно. Я думаю, только потому, что вы можете уволить их в большинстве случаев из вашего собственного кода, вы не должны.

Ответ 5

Вы можете сделать

var modal = {} as IModal 

Ответ 6

Так как я не нашел равного ответа в топе, и мой ответ другой. Я делаю:

modal: IModal = <IModal>{}

Ответ 7

Используя ваш интерфейс вы можете сделать

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.
  }
}

Ответ 8

Вот другой подход:

Вы можете просто создать дружественный ESLint объект, как этот

const modal: IModal = {} as IModal;

Или экземпляр по умолчанию, основанный на интерфейсе и с разумными значениями по умолчанию, если таковые имеются

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

Затем варианты экземпляра по умолчанию просто переопределяют некоторые свойства

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