Working with the DOM
Learn how to use TypeScript to interact with the DOM and create dynamic web pages.
TypeScript Interfaces and Classes: A Beginner's Guide
What are Interfaces?
Think of an interface as a contract. It defines what properties and methods an object should have. It's a way to specify a shape. It doesn't implement anything, just describes the structure.
For example, if we want to ensure that any object representing a person has a 'name' (string) and an 'age' (number), we can define an interface.
interface Person {
name: string;
age: number;
greet(): string; // Method signature
}
const john: Person = {
name: "John Doe",
age: 30,
greet() {
return `Hello, my name is ${this.name} and I am ${this.age} years old.`;
}
};
console.log(john.greet()); // Output: Hello, my name is John Doe and I am 30 years old.
If you try to create an object that claims to implement the `Person` interface but doesn't include all the required properties or has the wrong type for a property, TypeScript will give you an error. This helps prevent mistakes and ensures that your code is predictable.
Optional properties in interfaces can be declared with a question mark (?
):
interface Address {
street: string;
city: string;
zipCode?: string; // zipCode is optional
}
const myAddress: Address = {
street: "123 Main St",
city: "Anytown"
}; // No error, even without zipCode.
What are Classes?
A class is a blueprint for creating objects. It defines both the properties (data) and the methods (actions) that an object of that class will have. Unlike interfaces, classes can actually *implement* the behavior.
Here's an example of a simple `Car` class:
class Car {
make: string;
model: string;
year: number;
constructor(make: string, model: string, year: number) {
this.make = make;
this.model = model;
this.year = year;
}
getDescription(): string {
return `This is a ${this.year} ${this.make} ${this.model}.`;
}
}
const myCar = new Car("Toyota", "Camry", 2020);
console.log(myCar.getDescription()); // Output: This is a 2020 Toyota Camry.
* The `constructor` is a special method that's called when you create a new object of the class using the `new` keyword. It's used to initialize the object's properties. * `this` refers to the current object being created or used. * `getDescription` is a method that returns a string describing the car.
Classes support concepts like inheritance and access modifiers (public, private, protected), but we'll keep it simple for now.
Defining Structures with Interfaces and Creating Reusable Components with Classes
You can use interfaces to define the shape of data that your classes will work with. This promotes code reusability and maintainability.
Let's say we have an interface for something that can be logged:
interface Loggable {
log(): void;
}
Now, we can create a class that implements this interface:
class User implements Loggable {
username: string;
email: string;
constructor(username: string, email: string) {
this.username = username;
this.email = email;
}
log(): void {
console.log(`User: ${this.username} (${this.email})`);
}
}
const newUser = new User("johndoe", "john.doe@example.com");
newUser.log(); // Output: User: johndoe (john.doe@example.com)
The `implements Loggable` part tells TypeScript that the `User` class must have a `log` method that takes no arguments and returns nothing (void). If it doesn't, TypeScript will show an error.
This allows you to create a function that accepts anything that implements the `Loggable` interface:
function logObject(item: Loggable) {
item.log();
}
const anotherUser = new User("janedoe", "jane.doe@example.com");
logObject(newUser); // User: johndoe (john.doe@example.com)
logObject(anotherUser); // User: janedoe (jane.doe@example.com)
class Product implements Loggable {
name: string;
price: number;
constructor(name: string, price: number) {
this.name = name;
this.price = price;
}
log(): void {
console.log(`Product: ${this.name} - $${this.price}`);
}
}
const myProduct = new Product("Awesome Widget", 29.99);
logObject(myProduct); // Product: Awesome Widget - $29.99
In this example, we created a `Product` class that also implements Loggable. The `logObject` function can now take *any* object of a class that satisfies the `Loggable` interface. This promotes reusability because we can use the same `logObject` function for `User`, `Product` or any future class that implements the `Loggable` interface!