Як я можу створити об’єкт на основі визначення файлу інтерфейсу в TypeScript?


313

Я визначив такий інтерфейс:

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

Я визначаю таку змінну:

var modal: IModal;

Однак, коли я намагаюся встановити властивість modal, це дає мені повідомлення про те

"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>{};це те, що я шукав ;-) дякую!
Легенди

5
FYI, краще використовувати {} 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> {// цей рядок створює вміст екземпляра: '', форма: '', href: '', $ form: null, $ message: null, $ modal: null, $ submit: null}); // заповніть свій код `
Сонячний

за допомогою var modal= <abc>{}ми просто призначили модальний тип abc порожнього об'єкта, але де ми оголосили тип модального? я використовую typecript6.
Pardeep Jain

Це не спрацювало для мене. Мені довелося ініціалізувати весь об'єкт, як зазначено у прийнятій відповіді.
Рахул Сонванші


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.