What overriding means
A child class inherits its parent's methods, but sometimes an inherited method is nearly right and needs different behaviour. A puppy is a dog, yet it says Yip! where a grown dog says Woof!. Overriding means defining a method in the child with the same name as one in the parent. The child's version replaces the parent's for objects of the child class. The parent class is left untouched.
Why override instead of inventing a new name
You could give the puppy a method called yip. But then every piece of code that works with dogs would have to know which kind it holds, to decide between bark and yip. With an override, callers just call bark() and the right version runs for whatever object they have. The caller stays simple, and the differences live inside the classes.
How to override in TypeScript
You write the method again in the child, with the same name and a compatible signature. No special keyword is required on either class:
class Dog {
name: string;
constructor(name: string) { this.name = name; }
bark(): void {
console.log("Woof! I am " + this.name);
}
}
class Puppy extends Dog {
bark(): void {
console.log("Yip! I am " + this.name);
}
}
When bark is called on a Puppy, JavaScript looks for the method on the puppy's own class first and finds the override. When it is called on a plain Dog, it finds the original. The field name is inherited, which is why the overriding method can still use this.name.
Rules for the new method
The compiler checks that the override fits the parent's version, because code written for a Dog must still work when it receives a Puppy. If the child's method has an incompatible parameter list or return type, the compiler reports that the property is not assignable to the same property in the base type. An override may be more flexible than the original, for example by taking optional parameters, but it can't demand more or return something unrelated.
The optional override keyword
TypeScript also has an override modifier. Putting it before the method states your intention, and the compiler then checks that the parent has a method of that name:
class Puppy extends Dog {
override bark(): void {
console.log("Yip! I am " + this.name);
}
}
If you misspell the name, say override barkk(), the compiler reports that the member is not declared in the base class. Without the modifier, a misspelling would silently create a new method and the parent's bark would keep running. The lesson works without it.
Extending instead of replacing
An override can build on the parent's version by calling it through super:
class Puppy extends Dog {
bark(): void {
super.bark();
console.log("Yip!");
}
}
For a puppy named Q this prints Woof! I am Q and then Yip!. The lesson itself replaces the output completely, so it doesn't use super.
The exercise
The starter code has Dog with its bark, an empty Puppy class that extends it, and code that creates a puppy named "Buddy" and calls bark(). Run as it is, it prints Woof! I am Buddy, because the empty child inherits everything.
- Declare the override. Inside
Puppy, writebark(): void { }, the same name and return type as the parent's. - Fill in the body. Log
"Yip! I am "followed bythis.name.
class Dog {
name: string;
constructor(name: string) { this.name = name; }
bark(): void {
console.log("Woof! I am " + this.name);
}
}
class Puppy extends Dog {
bark(): void {
console.log("Yip! I am " + this.name);
}
}
const buddy: Puppy = new Puppy("Buddy");
buddy.bark();
The output is:
Yip! I am Buddy
The choice follows the object, not the variable's declared type. If you store the puppy in a variable typed as Dog, with const asDog: Dog = buddy;, then asDog.bark() still prints Yip! I am Buddy.
Common mistakes
- A different name.
Bark()orbarks()does not overridebark(). Names are case-sensitive, and the parent's method keeps running. - A different signature. Changing the parameters or the return type to something incompatible is a compile error.
- Forgetting
this.. The name comes from the field, so the body needsthis.name. - Wrong text. The new message starts with
Yip! I am, with the space before the name. - Expecting the parent to change. Overriding in
PuppyleavesDogas it was. A plainDogstill saysWoof!.
Key takeaways
- Defining a method with the same name in a child class overrides the parent's version for the child's objects.
- TypeScript needs no keyword, but
overridelets the compiler catch misspelt names. - The override must stay compatible with the parent's method signature.
- Use
super.method()to run the parent's version from inside the override.