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


313

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

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"

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

Ответы:


426

Если вы создаете «модальную» переменную в другом месте и хотите сообщить 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
Спасибо. Я надеялся избавиться от необходимости определять все модальное содержимое изначально. Было бы проще, если бы вместо интерфейса я определил Modal как класс со свойствами, а затем использовал new и конструктор для установки всех начальных значений?

1
Да, вы можете определить класс, и тогда вам придется создавать новые экземпляры только тогда, когда они вам нужны. Вам нужен пример?
Фентон

2
Я добавил пример и заметку об интерфейсе.
Фентон

21
var modal = <IModal>{};это то, что я искал ;-) спасибо!
Legends

5
К вашему сведению, лучше использовать {} as IModal, чем <IModal>{}. Это устраняет неоднозначность в грамматике языка при использовании <foo>утверждений стиля в JSX. Подробнее . И, конечно, использовать letили constвместо var.
Алекс Клаус

191

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

var modal = <IModal>{};

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

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

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

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

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


1
`Добавить к вышеупомянутому комментарию. Чтобы вызвать функцию «updateModal (IModal modalInstance) {}», вы можете создать встроенный экземпляр интерфейса «IModal», например: // здесь есть некоторый код, где доступны функция updateModal и IModal: updateModal (<IModal> {// эта строка создает содержимое экземпляра: '', form: '', href: '', $ form: null, $ message: null, $ modal: null, $ submits: null}); // завершить ваш код `
Солнечный

используя var modal= <abc>{}только что назначенный модальный тип abc пустого объекта, но где мы объявили модальный тип? Я использую TypeScript6.
Пардип Джайн

Это не сработало для меня, я должен был инициализировать весь объект, как указано в принятом ответе.
Рахул Сонванши

52

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

let a = {} as MyInterface;

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


22

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

В большинстве случаев лучше всего использовать класс и создавать его экземпляры , потому что вы используете 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;
    //...
}

С другой стороны, например, во время модульного тестирования вашего кода (если вы не часто применяете разделение задач), вы можете принять недостатки для повышения производительности. Вы можете применять другие методы для создания макетов, в основном для больших сторонних * .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 обеспечивает новый уровень абстракции, если используется разумно и последовательно. Я думаю, просто потому, что вы можете отклонить их в большинстве случаев из своего собственного кода, вы не должны этого делать.



12

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

modal: IModal = <IModal>{}

2

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

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

Вот еще один подход:

Вы можете просто создать дружественный 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
}

1

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

Для тех, кто заинтересован в некоторых других надежных и компактных решениях :

Вариант 1: создание анонимного класса, который реализует интерфейс:

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

Вариант 2: Создать служебную функцию:

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

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

0

Вы можете установить значения по умолчанию, используя Class.

Без конструктора классов:

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}

С конструктором класса

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}
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.