ChatGPT解决这个技术问题 Extra ChatGPT

How can I create an object based on an interface file definition in TypeScript?

I have defined an interface like this:

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

I define a variable like this:

var modal: IModal;

However, when I try to set the property of modal it gives me a message saying that

"cannot set property content of undefined"

Is it okay to use an interface to describe my modal object and if so how should I create it?


F
Fenton

If you are creating the "modal" variable elsewhere, and want to tell TypeScript it will all be done, you would use:

declare const modal: IModal;

If you want to create a variable that will actually be an instance of IModal in TypeScript you will need to define it fully.

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

Or lie, with a type assertion, but you'll lost type safety as you will now get undefined in unexpected places, and possibly runtime errors, when accessing modal.content and so on (properties that the contract says will be there).

const modal = {} as IModal;

Example Class

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

const modal = new Modal();

You may think "hey that's really a duplication of the interface" - and you are correct. If the Modal class is the only implementation of the IModal interface you may want to delete the interface altogether and use...

const modal: Modal = new Modal();

Rather than

const modal: IModal = new Modal();

Thanks. I was hoping to get away from having to define all of the modal contents initially. Would it be easier if instead of an interface I defined Modal as a class with properties and then used new and a constructor to set up all of the initial values?
Yes - you could define a class and then you would only have to create new instances when you needed them. Do you need an example?
I have added an example and a note about the interface.
var modal = <IModal>{}; this is what I was looking for ;-) thanks!
FYI, it's better to use {} as IModal rather than <IModal>{}. It removes an ambiguity in the language grammar when using <foo> style assertions in JSX. Read more. And of course, use let or const instead of var.
u
user3180970

If you want an empty object of an interface, you can do just:

var modal = <IModal>{};

The advantage of using interfaces in lieu of classes for structuring data is that if you don't have any methods on the class, it will show in compiled JS as an empty method. Example:

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

compiles into

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

which carries no value. Interfaces, on the other hand, don't show up in JS at all while still providing the benefits of data structuring and type checking.


` To add on to the above comment. To call a function "updateModal(IModal modalInstance) { }", you can create an inline instance of the interface 'IModal', like this: //some code here, where the updateModal function & IModal are accessible: updateModal( { //this line creates an instance content: '', form: '', href: '', $form: null, $message: null, $modal: null, $submits: null }); //complete off your code `
by using var modal= <abc>{} we just have assigned modal of type abc of empty object but where we have declared type of modal ? i am using typescript6.
This did not work for me I had to initialize the whole object as stated in the accepted answer.
g
geg

If you are using React, the parser will choke on the traditional cast syntax so an alternative was introduced for use in .tsx files

let a = {} as MyInterface;

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


K
Kangudie Muanza - Killmonger

You can do

var modal = {} as IModal 

U
Ursegor

I think you have basically five different options to do so. Choosing among them could be easy depending on the goal you would like to achieve.

The best way in most of the cases to use a class and instantiate it, because you are using TypeScript to apply type checking.

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

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

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

    foo(param: string): void {
    }
}

Even if other methods are offering easier ways to create an object from an interface you should consider splitting your interface apart, if you are using your object for different matters, and it does not cause interface over-segregation:

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

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

On the other hand, for example during unit testing your code (if you may not applying separation of concerns frequently), you may be able to accept the drawbacks for the sake of productivity. You may apply other methods to create mocks mostly for big third party *.d.ts interfaces. And it could be a pain to always implement full anonymous objects for every huge interface.

On this path your first option is to create an empty object:

 var modal = <IModal>{};

Secondly to fully realise the compulsory part of your interface. It can be useful whether you are calling 3rd party JavaScript libraries, but I think you should create a class instead, like before:

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

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

Thirdly you can create just a part of your interface and create an anonymous object, but this way you are responsible to fulfil the contract

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

    }
};

Summarising my answer even if interfaces are optional, because they are not transpiled into JavaScript code, TypeScript is there to provide a new level of abstraction, if used wisely and consistently. I think, just because you can dismiss them in most of the cases from your own code you shouldn't.


r
rbento

Here is another approach:

You can simply create an ESLint friendly object like this

const modal: IModal = {} as IModal;

Or a default instance based on the interface and with sensible defaults, if any

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

Then variations of the default instance simply by overriding some properties

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

P
Paul Rooney

Since I haven't found an equal answer in the top and my answer is different. I do:

modal: IModal = <IModal>{}

N
Naveed Ullah

There are 5 ways to use the interface.

interface IStudent {
      Id: number;
      name: string;
    }
    
    
    Method 1. all fields must assign data.
     const  obj1: IStudent = { Id: 1, name: 'Naveed' };  
    
    Method 2. my favorite one
    const obj2 = { name: 'Naveed' } as IStudent ;
    
    Method 3.
    const obj3 = <IStudent >{name: 'Naveed'}; 
    
    Method 4. use partial interface if all fields not required.
    const  obj4: Partial<IStudent > = { name: 'Naveed' };  
    
    Method 5. use ? Mark with interface fields if all fields not required.
    const  obj5: IStudent = {  name: 'Naveed' };  

P
Pmag

Since the question includes usage of TypeScript, replacing

var modal: IModal;

by

let modal: IModal = {} as IModal;

should answer the question.


no, create an empty obejct: modal = {}; with no properties inside it.
S
Stephen Paul

Many of the solutions so far posted use type assertions and therefor do not throw compilation errors if required interface properties are omitted in the implementation.

For those interested in some other robust, compact solutions:

Option 1: Instantiate an anonymous class which implements the interface:

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

Option 2: Create a utility function:

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

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

G
GorvGoyl

You can set default values using Class.

Without Class Constructor:

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}

With Class Constructor

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}

M
M Komaei
let deletedQuestionsDto = { examId: this.examId, questionId: q.id } as DeletedQuestionsDto;

P
Paul Rooney

Using your interface you can do

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

F
Freddy

You actually don't need the class to create the object. You can direct do this:

interface IModal {
    content: string;
    form: string;
}

onButtonSaveClick() {
    let myModalClass: IModal = {
        content: 'foo content',
        form: 'foo form'
    }
}

d
dipenparmar12

Here another solution what i am using frequently. However I am not sure is good practice or not, please comment below if not.

/// Interface
export default interface BookInterface {
  title: string,
  author: string,
  id: any
}

/// Creating Class
export class BookClass implements BookInterface {
  title: string;
  author: string;
  id: any;

  constructor(title: string, author: string, id: any) {
    this.title = title;
    this.author = author;
    this.id = id;
  }
}

/// How to use it
let book: BookInterface = new BookClass(title, author, id);

Thanks :)


Basically its bad practice, because Interfaces are only used at compile time and result in slim minified js files, while classes will be compiled to js classes (functions) which add to code and complexity