How to Create an Object Using an Interface in TypeScript

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

I have an interface defined as follows:

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 a property of modal, I get the error message:

“cannot set property content of undefined”

Is it appropriate to use an interface to describe my modal object, and how should I properly create an object based on the IModal interface in TypeScript?

I’ve had a lot of experience working with TypeScript, and in cases like this, it’s important to first understand how TypeScript treats variables declared with an interface. If you’re declaring the modal variable elsewhere and just want TypeScript to recognize its type, you can use:

declare const modal: IModal;

However, if you want to create an object based on the IModal interface, you’ll need to fully initialize it with values. Here’s an example:

const modal: IModal = {
    content: '',
    form: '',
    href: '',
    $form: null as any, // Replace null with actual JQuery objects as needed
    $message: null as any,
    $modal: null as any,
    $submits: null as any
};

In this case, initializing the modal object will prevent the “cannot set property content of undefined” error, ensuring that the modal object adheres to the IModal interface definition from the start.

Another method you can consider, though it sacrifices some type safety, is using a type assertion to tell TypeScript to treat an empty object as an instance of IModal. Here’s how you can do that:

const modal = {} as IModal;

However, if you’re aiming for a more structured approach that’s still based on the interface, you can implement the interface via a class. This provides more flexibility while adhering to the interface:

class Modal implements IModal {
    content: string = '';
    form: string = '';
    href: string = '';
    $form: JQuery = null as any;
    $message: JQuery = null as any;
    $modal: JQuery = null as any;
    $submits: JQuery = null as any;
}

const modal = new Modal();

This setup ensures that any Modal object follows the IModal structure, and if Modal is your only implementation, you might prefer using the class directly:

const modal: Modal = new Modal();

This can simplify your code, avoiding redundancy between the interface and class if Modal is the sole implementation. This way, you can still follow the principles of TypeScript’s create object from interface while using a class-based approach.

Both approaches mentioned above work great, but I’d like to emphasize the trade-off when using type assertions. If you choose to go with:

let modal: IModal = {} as IModal;

You’re essentially telling TypeScript that you’re sure the object will conform to the IModal interface, even though it may not be fully initialized. This can lead to runtime errors if you try to access properties before they’ve been properly set.

For example, accessing modal.content before assigning it could still cause an issue since it’s not guaranteed to exist right away.

A better, more type-safe solution is to fully initialize the modal object, as mentioned before, or use a class that implements the interface for a more controlled and safer creation of the modal object:

class Modal implements IModal {
    content: string = '';
    form: string = '';
    href: string = '';
    $form: JQuery = null as any;
    $message: JQuery = null as any;
    $modal: JQuery = null as any;
    $submits: JQuery = null as any;
}

const modal = new Modal();

This method allows TypeScript to enforce the structure, ensuring your modal adheres to the interface without relying on risky type assertions.