Objects and Interfaces
Dive into defining objects and using interfaces to define contracts for your data. Learn about optional properties and readonly modifiers.
TypeScript Objects and Interfaces: A Beginner's Guide
What are Objects in TypeScript?
In TypeScript (and JavaScript), an object is a collection of key-value pairs. Think of it like a real-world object, like a person. A person has properties such as a name, age, and address. In code, we represent these properties as keys, and the actual value (e.g., "John", 30, "123 Main St") as the value.
Here's a simple example of a person object in TypeScript:
const person = {
name: "Alice",
age: 25,
city: "New York"
};
console.log(person.name); // Output: Alice
console.log(person.age); // Output: 25
This is a straightforward way to create an object, but TypeScript's power comes from its ability to define the shape of these objects using interfaces.
What are Interfaces in TypeScript?
An interface in TypeScript is a way to define a contract for the structure of an object. It specifies what properties an object should have, and the data type of those properties. Interfaces don't hold any data themselves; they just describe the expected shape. This is what gives TypeScript its type-checking capabilities.
Think of it like a blueprint for a house. The blueprint specifies the number of rooms, their sizes, and the materials used. It doesn't build the house, but it provides a detailed plan that must be followed. An interface does the same for objects.
Here's an example of defining an interface for a person:
interface Person {
name: string;
age: number;
city: string;
}
Now, we can use this interface to ensure that our person objects conform to the defined structure:
const person1: Person = {
name: "Bob",
age: 30,
city: "London"
};
// This would cause a TypeScript error because 'occupation' is not in the Person interface
// const person2: Person = {
// name: "Charlie",
// age: 22,
// city: "Paris",
// occupation: "Student"
// };
The TypeScript compiler will now check that any object assigned to a variable of type Person
has all the required properties (name
, age
, and city
) and that those properties have the correct data types.
Defining Objects Using Interfaces
Let's break down how to define objects using interfaces more clearly:
- Define the Interface: First, you define the interface using the
interface
keyword, followed by the name of the interface, and then a block of code{}
containing the properties and their types. - Specify Properties and Types: Inside the interface, you define the properties using the syntax
propertyName: dataType;
. For example,name: string;
means thename
property should be a string. Common data types includestring
,number
,boolean
,any
(use sparingly!), and other interfaces. - Create Objects Using the Interface: When you create an object, you tell TypeScript that the object should conform to a specific interface by using a colon
:
after the variable name, followed by the interface name (e.g.,const myObject: MyInterface = ...;
).
Here's a more comprehensive example:
interface Address {
street: string;
city: string;
zipCode: string;
}
interface Employee {
id: number;
name: string;
age: number;
address: Address; // Using another interface as a type!
}
const employee1: Employee = {
id: 123,
name: "David",
age: 35,
address: {
street: "456 Oak Ave",
city: "Chicago",
zipCode: "60611"
}
};
console.log(employee1.address.city); // Output: Chicago
In this example, we have two interfaces: Address
and Employee
. The Employee
interface uses the Address
interface as the type for its address
property, illustrating how interfaces can be composed together.
Optional Properties
Sometimes, you might want a property to be optional. This means the object doesn't have to have that property to be considered valid according to the interface. You can make a property optional by adding a question mark ?
after the property name in the interface definition.
interface Product {
id: number;
name: string;
description?: string; // 'description' is optional
price: number;
}
const product1: Product = {
id: 1,
name: "Laptop",
price: 1200
};
const product2: Product = {
id: 2,
name: "Keyboard",
description: "Mechanical Keyboard",
price: 100
};
console.log(product1.description); // Output: undefined
console.log(product2.description); // Output: Mechanical Keyboard
In this example, the description
property is optional. product1
doesn't have it, and TypeScript doesn't complain. product2
does have it, and that's also perfectly valid.
Readonly Modifiers
The readonly
modifier allows you to make a property immutable after the object is created. This means you can't change the value of that property once it's been set.
interface Circle {
readonly radius: number;
color: string;
}
const circle1: Circle = {
radius: 5,
color: "blue"
};
// This would cause a TypeScript error because 'radius' is readonly
// circle1.radius = 10;
circle1.color = "red"; // This is allowed because 'color' is not readonly
console.log(circle1.radius); // Output: 5
Using readonly
is useful for properties that should never change after initialization, such as IDs or configuration values. It helps prevent accidental modifications and makes your code more robust.