Question
I have defined a TypeScript interface like this:
interface IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
Then I declare a variable like this:
let modal: IModal;
However, when I try to assign a property such as modal.content, I get an error similar to:
Cannot set property 'content' of undefined
Is it valid to use an interface to describe my modal object, and if so, how should I actually create and initialize the object?
Short Answer
By the end of this page, you will understand what a TypeScript interface does, why let modal: IModal; does not create an object, and how to properly initialize an object that matches an interface. You will also see common patterns for object creation, optional properties, and safer ways to avoid undefined errors.
Concept
A TypeScript interface describes the shape of an object. It tells TypeScript what properties an object should have and what types those properties must use.
For example:
interface IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
This does not create an object. It only defines a contract.
When you write:
let modal: IModal;
you are only declaring a variable that is expected to hold an object matching IModal later. At that moment, modal is still undefined.
So if you do this next:
modal.content = "Hello";
JavaScript tries to access the content property on undefined, which causes the runtime error.
Why this matters
In real programs, interfaces help you:
- document object structure clearly
- catch type mistakes during development
- improve autocomplete and editor support
- make function parameters and return values safer
But interfaces exist only at compile time. They do not allocate memory or create runtime values.
The key idea
- Interface = blueprint or contract
- Object literal / class instance / factory function = actual object in memory
To use an interface, you must still create a real object:
let modal: IModal = {
content: "",
form: "",
href: "",
$form: $("form"),
$message: $(".message"),
$modal: $(".modal"),
$submits: $("button[type='submit']")
};
Mental Model
Think of an interface like an architectural drawing for a house.
- The drawing tells you how many rooms the house should have.
- It does not build the house.
- Declaring
let modal: IModal;is like saying, "I will have a house that follows this plan." - But until the house is actually built, there is nothing to walk into.
So:
interface IModal { ... }= the planlet modal: IModal;= a promise that a matching object will existlet modal: IModal = { ... }= the actual house being built
Syntax and Examples
Basic syntax
1. Define the interface
interface IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
2. Create an object that matches it
let modal: IModal = {
content: "Modal body",
form: "loginForm",
href: "/login",
$form: $("#loginForm"),
$message: $("#message"),
$modal: $("#myModal"),
$submits: $("button[type='submit']")
};
Now modal is a real object, so you can safely access and update its properties:
modal.content = "Updated content";
modal.href = "/signup";
Creating first, assigning later
You can also initialize it in multiple steps, but the object must exist first:
let modal: IModal = {
content: "",
form: "",
href: "",
$form: $(""),
$message: $(""),
$modal: $(""),
$submits: $("")
};
modal.content = "Welcome";
modal.form = "signupForm";
Optional properties when not all values are ready yet
If some values are not available immediately, make them optional:
interface IModal {
content: string;
form: string;
href: string;
$form?: JQuery;
$message?: JQuery;
$modal?: JQuery;
$submits?: JQuery;
}
let modal: IModal = {
content: "",
form: "",
href: ""
};
This allows you to create the object before all jQuery references are assigned.
Using a factory function
A common pattern is to return a properly shaped object from a function:
function createModal(): IModal {
return {
content: "",
form: "",
href: "",
$form: $("form"),
$message: $(".message"),
$modal: $(".modal"),
$submits: $("button[type='submit']")
};
}
const modal = createModal();
This is useful when you need to build the same kind of object in several places.
Step by Step Execution
Consider this code:
interface IModal {
content: string;
form: string;
href: string;
}
let modal: IModal;
modal.content = "Hello";
What happens step by step
Step 1: The interface is declared
interface IModal {
content: string;
form: string;
href: string;
}
TypeScript learns that any IModal object must have three string properties.
Step 2: The variable is declared
let modal: IModal;
This creates a variable named modal, but no object is assigned to it yet.
At runtime, its value is effectively:
undefined
Step 3: A property is assigned
modal.content = "Hello";
JavaScript now tries to do this:
- look at the value of
modal - find its
contentproperty - assign
"Hello"
But modal is undefined, so there is no object to update.
That causes the runtime error.
Correct version
interface IModal {
content: string;
form: string;
href: string;
}
let modal: IModal = {
content: "",
form: "",
href: ""
};
modal.content = "Hello";
Step-by-step for the correct version
- The interface defines the required properties.
modalis assigned a real object with those properties.modal.content = "Hello"works becausemodalnow points to an actual object.
Real World Use Cases
Interfaces are commonly used anywhere you want consistent object structure.
UI state objects
A modal, dropdown, or form component often has related fields grouped into one object:
interface ModalState {
isOpen: boolean;
title: string;
content: string;
}
API response shapes
When fetching data from a server, interfaces describe expected fields:
interface User {
id: number;
name: string;
email: string;
}
Function parameters
Interfaces help functions accept structured input safely:
interface LoginData {
username: string;
password: string;
}
function submitLogin(data: LoginData) {
console.log(data.username);
}
Configuration objects
Many libraries use configuration objects, and interfaces document them clearly:
interface RequestOptions {
method: string;
timeout: number;
}
DOM or jQuery wrappers
Your example fits this pattern well: collecting useful references and metadata in one object for reuse across event handlers and UI logic.
Real Codebase Usage
In real projects, developers rarely leave typed variables uninitialized if they plan to assign properties immediately.
Common patterns
Initialize immediately
This is the simplest and most common pattern:
const modal: IModal = {
content: "",
form: "",
href: "",
$form: $("#form"),
$message: $("#message"),
$modal: $("#modal"),
$submits: $(".submit")
};
Use optional properties for delayed setup
If some values are assigned later:
interface IModal {
content: string;
form: string;
href: string;
$form?: JQuery;
}
This is useful during progressive initialization.
Use a builder or factory function
Useful when object creation logic is repeated:
function buildModal(selector: string): IModal {
return {
content: "",
form: "",
href: selector,
$form: $(`${selector} form`),
$message: $(`${selector} .message`),
$modal: $(selector),
$submits: $(`${selector} button[type='submit']`)
};
}
Validate before use
If a value might be missing, developers often guard before accessing it:
if (modal) {
modal.content = "Ready";
}
But in strongly typed TypeScript code, it is usually better to initialize correctly instead of relying on repeated checks.
Separate data from DOM references
In larger codebases, developers may split raw data and DOM elements into separate interfaces for clarity:
interface ModalData {
content: string;
form: string;
href: string;
}
interface ModalElements {
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
Common Mistakes
1. Thinking an interface creates an object
Broken example:
interface IModal {
content: string;
}
let modal: IModal;
modal.content = "Hi";
Problem:
modalis declared but not initialized- no real object exists yet
Fix:
let modal: IModal = { content: "" };
2. Declaring required properties but not providing them
Broken example:
interface IModal {
content: string;
form: string;
}
let modal: IModal = {
content: "Hello"
};
Problem:
formis required but missing
Fix:
let modal: IModal = {
content: "Hello",
form: "login"
};
3. Using type assertions to silence errors unsafely
Broken example:
let modal = {} as IModal;
modal.content = "Hello";
Why this is risky:
- it tells TypeScript to trust you
- missing properties may still cause bugs later
Better:
let modal: IModal = {
content: "",
form: "",
href: "",
$form: $(""),
$message: $(""),
$modal: $(""),
$submits: $("")
};
4. Forgetting that optional properties may still be undefined
interface IModal {
content: string;
$form?: JQuery;
}
If $form is optional, this may be unsafe:
modal.$form.hide();
Safer:
modal.$form?.hide();
5. Mixing compile-time safety with runtime behavior
TypeScript can check shapes during development, but it does not magically initialize variables at runtime. You still need normal JavaScript object creation.
Comparisons
| Concept | What it does | Creates a runtime object? | Best use |
|---|---|---|---|
interface | Describes object shape | No | Defining contracts for objects |
type | Describes a type, often similar to an interface | No | Flexible type composition |
| Object literal | Creates an actual object | Yes | Simple object creation |
class | Defines a blueprint for instances with behavior | Yes, when instantiated with new | Objects with methods and reusable behavior |
Interface vs class
interface IModal {
content: string;
}
class Modal implements IModal {
content: string;
constructor() {
this.content = "";
}
}
const modal = new Modal();
- Use an interface when you only need to describe shape.
- Use a class when you need methods, constructors, or object behavior.
Interface vs type alias
type Modal = {
content: string;
form: string;
};
For simple object shapes, interface and type are often similar. In many codebases, interface is preferred for object contracts and type is used more for unions or composed types.
Declared variable vs initialized variable
| Code | Result |
|---|---|
let modal: IModal; | Variable exists, value is undefined |
let modal: IModal = { ... }; | Variable holds a real object |
Cheat Sheet
interface IModal {
content: string;
form: string;
href: string;
$form: JQuery;
$message: JQuery;
$modal: JQuery;
$submits: JQuery;
}
Key rule
An interface defines shape only. It does not create an object.
Wrong
let modal: IModal;
modal.content = "Hello"; // runtime error
Right
let modal: IModal = {
content: "",
form: "",
href: "",
$form: $("#form"),
$message: $("#message"),
$modal: $("#modal"),
$submits: $(".submit")
};
Optional properties
interface IModal {
content: string;
$form?: JQuery;
}
Factory function
function createModal(): IModal {
return {
content: "",
form: "",
href: "",
$form: $("#form"),
$message: $("#message"),
$modal: $("#modal"),
$submits: $(".submit")
};
}
Remember
interface= contract- object literal = actual value
- required properties must be present
- optional properties may be
undefined - TypeScript checks types, but JavaScript still controls runtime behavior
FAQ
Does a TypeScript interface create an object?
No. An interface only describes the required structure of an object.
Why is let modal: IModal; undefined?
Because it declares the variable type but does not assign any actual object to it.
How do I create an object that matches an interface?
Assign an object literal, return one from a function, or create a class instance that matches the interface.
Can I assign properties later instead of all at once?
Yes, but the object itself must exist first. If some properties are not ready yet, make them optional or provide placeholder values.
Should I use an interface for a modal object?
Yes. It is a good use case if you want a clear, typed structure for related modal properties.
Is {} as IModal a good solution?
Usually not for beginners. It bypasses useful safety checks and can hide missing-property bugs.
When should I use a class instead of an interface?
Use a class if you need constructors, methods, or reusable behavior. Use an interface when you only need to describe object shape.
Mini Project
Description
Build a small typed modal configuration object in TypeScript. This project demonstrates the main lesson from the question: an interface defines the expected structure, but you must still create a real object before using its properties. It also shows how to update the object safely after initialization.
Goal
Create and use a modal object that follows an interface without causing undefined property errors.
Requirements
- Define an interface for a modal object with at least
content,form, andhref. - Create a real object that matches the interface.
- Update the object after creation.
- Add a function that prints modal information.
- Avoid any access on an uninitialized variable.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.