TypeScript
Completed
-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
149: The override Keyword
You've already spent a lot of time working with inheritance and polymorphism. You know that if you define a method in a base class, you can redefine it in a child class to change its behavior. For a long time, TypeScript just trusted you to get the names right. But in a large codebase, that trust is a liability. That's where the override keyword comes in.
Building a combat system for a RPG
I want to build a simple combat system. We'll start with a base class called GameCharacter. Every character should be able to take damage, but how they handle that damage depends on what kind of character they are.
class GameCharacter {
hp: number = 100;
takeDamage(amount: number) {
this.hp -= amount;
console.log(`Character took ${amount} damage. HP is now ${this.hp}`);
}
}
Now, I'll create a BossCharacter. Bosses usually have armor, so they shouldn't take the full amount of damage. I'll redefine the takeDamage method to implement this logic.
class BossCharacter extends GameCharacter {
override takeDamage(amount: number) {
const reducedDamage = amount * 0.5;
super.takeDamage(reducedDamage);
console.log("The boss's armor absorbed half the damage!");
}
}
By adding override here, I'm telling TypeScript: "I am intentionally replacing a method that exists in the parent class." If I'm right, everything works fine. If I'm wrong—maybe because of a typo—TypeScript will scream at me immediately.
The danger of "silent" failures
Here is where things usually go wrong in big projects. Imagine I'm refactoring the base class. I decide that takeDamage is too generic, and I want to rename it to applyDamage to be more precise across the whole engine.
I'll make that change in the base class now:
class GameCharacter {
hp: number = 100;
applyDamage(amount: number) { // Renamed from takeDamage
this.hp -= amount;
console.log(`Character took ${amount} damage. HP is now ${this.hp}`);
}
}
Now, look at what happens to my BossCharacter. Because I used the override keyword, TypeScript throws a compiler error: "This member cannot have an 'override' modifier because it is not overriding any member of the base class."
This is a lifesaver. If I hadn't used override, TypeScript would have just assumed I was adding a brand new method called takeDamage to the BossCharacter class. The code would still compile, but when the game engine called applyDamage on a boss, it would use the base class logic and ignore the armor reduction entirely. That's a bug that could take hours to track down in a real game.
When to actually use it
You might be wondering if this is just extra typing for no reason. I'll be honest: in a small file with two classes, it feels like overkill. But once you're working in a team where someone else might rename a method in a base class you don't even know exists, override becomes your insurance policy.
I highly recommend making it a habit to use it every single time you redefine a parent method. It transforms a potential runtime bug into a simple compile-time fix.
📋 Practical Task
Implementing a Smart Home Device Registry
You are building a system to manage smart home devices. You have a base class SmartDevice with a method called getStatus(). Your task is to create a subclass called SmartThermostat that provides a more detailed status report.
Requirements:
- Create a
SmartDeviceclass with agetStatus()method that returns the string"Device is online". - Create a
SmartThermostatclass that extendsSmartDevice. - In
SmartThermostat, use theoverridekeyword to redefinegetStatus(). It should return"Thermostat is online. Current temp: 72°F". - To test your implementation, intentionally rename the method in
SmartDevicetofetchStatus()and observe the TypeScript error produced by theoverridekeyword in the subclass. Once you see the error, rename it back togetStatus()to fix the build.
There are no comments for now.