Start learning free

LESSON 562 OF 573 · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

Employees and Managers in TypeScript: extends, super and Overriding

Practice O(1) Read the full explanation

A company pays every employee a salary. A manager is an employee too, but earns a bonus on top of the salary. Write the two classes so that a manager reuses everything an employee has, and changes only how its pay is worked out.

Implement the class Employee:

  • Employee(name, salary) creates an employee. The name and the salary are private to Employee.
  • pay() returns the salary.
  • describe() returns the text <name> earns <pay>, where the amount is what pay() returns, for example Ana earns 3000.

and the class Manager, which inherits from Employee:

  • Manager(name, salary, bonus) lets the parent's constructor store the name and the salary, and stores the bonus itself, private to Manager.
  • pay() returns the parent's pay() plus the bonus. Call the parent's version, as in the lesson Calling the Parent Method: the salary is private to Employee, and the parent's pay() is what knows how an employee is paid.
  • describe() is not written again: Manager inherits it unchanged. Because describe() calls pay(), a manager's description shows the manager's pay, bonus included.

The input is a list of people, one per line: employee name salary or manager name salary bonus. For each line, the code that tests your classes creates that object and prints what its describe() returns, on a line of its own. The starter code spells these names the way your language does.

 

Example 1:

Input:
    employee Ana 3000
    manager Bob 4000 1000
Output:
    Ana earns 3000
    Bob earns 5000
Explanation:
Ana's pay is her salary. Bob's pay is the parent's pay, his salary 4000, plus his bonus 1000.
Bob's describe() is Employee's describe(), but the pay() it calls is Manager's.

Example 2:

Input:
    manager Cleo 5000 0
    employee Dan 5000
Output:
    Cleo earns 5000
    Dan earns 5000
Explanation: A manager whose bonus is 0 earns exactly the salary, like an employee.

Example 3:

Input:
    manager Eve 7000 2500
    employee Finn 2800
    employee Gus 3100
    manager Hana 6000 500
Output:
    Eve earns 9500
    Finn earns 2800
    Gus earns 3100
    Hana earns 6500
Explanation: Employees and managers come in any order, and each object keeps its own name and numbers.

 

Constraints:

  • 0 <= salary <= 106
  • 0 <= bonus <= 106
  • A name is one word of 1 to 20 English letters. Two people may have the same name.
  • At most 100 people per test case.
STEP 1 OF 9
    Ctrl + Enter to check

    TYPESCRIPT · OBJECT-ORIENTED PROGRAMMING - CHALLENGES

    Employees And Managers in TypeScript, explained

    Problem overview

    A company pays each employee a salary. A manager is an employee too, with a bonus on top. The task is two classes in which Manager reuses everything Employee has and changes only how the pay is worked out.

    • Employee(name, salary) keeps both private. pay() returns the salary. describe() returns text like Ana earns 3000, using what pay() returns.
    • Manager(name, salary, bonus) extends Employee. It stores the bonus privately, and its pay() returns the parent's pay plus the bonus. It doesn't rewrite describe().

    Approach

    Each class owns its own data. The salary is private to Employee, so Manager can't read it. It doesn't need to: super.pay() runs the parent's version, which knows how to give the salary. describe() calls this.pay(). On a manager, this.pay() is the manager's version, so the inherited describe() shows the bonus without any extra code.

    Step by step

    1. Employee's private fields name and salary. Private means not even Manager can use them.
    2. Constructor stores both parameters in the fields.
    3. pay returns this.salary.
    4. describe returns the name, then " earns ", then this.pay(), joined with +. Adding a number to a string turns the number into text.
    5. Manager extends Employee and declares its own private bonus.
    6. Constructor. First super(name, salary), which runs the parent's constructor and fills in the private name and salary. TypeScript requires this call before the constructor uses this.
    7. Store the bonus in this.bonus.
    8. Override pay with super.pay() + this.bonus.

    The solution in TypeScript

    class Employee {
        private name: string;
        private salary: number;
    
        constructor(name: string, salary: number) {
            this.name = name;
            this.salary = salary;
        }
    
        pay(): number {
            return this.salary;
        }
    
        describe(): string {
            return this.name + " earns " + this.pay();
        }
    }
    
    class Manager extends Employee {
        private bonus: number;
    
        constructor(name: string, salary: number, bonus: number) {
            super(name, salary);
            this.bonus = bonus;
        }
    
        pay(): number {
            return super.pay() + this.bonus;
        }
    }
    
    • super.pay() versus this.pay(). Inside Manager.pay, this.pay() would call the same method again, forever. super.pay() calls Employee's version.
    • Overriding. A method with the same name in the subclass replaces the parent's for objects of the subclass, even when the call is made inside the parent's code, as in describe.
    • Private is for the compiler. A line such as b.salary outside the class is reported as an error (the property is private and only accessible within Employee), but TypeScript still writes JavaScript and the value would be read at run time.

    Using the classes

    const a = new Employee("Ana", 3000);
    const b = new Manager("Bob", 4000, 1000);
    console.log(a.describe());
    console.log(b.describe());
    console.log(new Manager("Cleo", 5000, 0).describe());
    console.log(new Manager("Hana", 6000, 500).describe());
    const staff: Employee[] = [a, b];
    for (const s of staff) {
        console.log(s.pay());
    }
    
    Ana earns 3000
    Bob earns 5000
    Cleo earns 5000
    Hana earns 6500
    3000
    5000
    

    A manager can be used wherever an employee is expected: in the list typed Employee[], the call s.pay() picks the right version for each object. A manager with a bonus of 0 earns exactly the salary.

    How the call finds the right pay

    A single call such as describe() can run different code depending on the object. Take a list that mixes both kinds of people:

    Objectdescribe() returns
    new Employee("Ana", 3000)Ana earns 3000
    new Manager("Bob", 4000, 1000)Bob earns 5000
    new Manager("Eve", 7000, 2500)Eve earns 9500
    new Employee("Finn", 2800)Finn earns 2800

    There is only one describe, written in Employee. When it runs on Bob it calls this.pay(), and because Bob is a Manager object, that call goes to Manager's pay. A manager is also an employee: instanceof Employee is true for both, while instanceof Manager is true only for the managers.

    This is the reason to build describe on pay() and not on the field: a change to how managers are paid then needs no change to describe.

    What goes wrong without super

    Two natural mistakes are worth seeing. If Manager.pay calls this.pay() for the base amount, the method calls itself, and the program stops with RangeError: Maximum call stack size exceeded. If Manager.pay returns only this.bonus, the program runs, but Bob's description reads Bob earns 1000: the salary is lost. Writing super.pay() + this.bonus avoids both, because it asks the parent for exactly the part the parent owns.

    The same structure works for any "base plus extra" rule. The subclass adds its own data and its own change to one method, and everything else is inherited.

    Edge cases and common mistakes

    • Forgetting super(...). A subclass constructor must call it before using this, or the compiler reports an error.
    • Reading this.salary in describe. It would ignore the bonus for managers. Call this.pay().
    • Writing describe again in Manager. It is unnecessary; the inherited one already works.
    • Using this.pay() inside Manager.pay. It recurses until the program runs out of stack.

    More cases to try

    • A salary of 0 and a bonus of 0 still describe as earns 0. The text comes from joining a string with a number, and 0 is a valid number to print.
    • Two people may share a name. Each object keeps its own private fields, so Ana the employee and Ana the manager do not affect each other.
    • Building a manager with the arguments in the wrong order, such as bonus before salary, compiles, because all three are in the right types, and gives the wrong pay. Check the order against the signature: name, salary, bonus.

    Key points

    • extends makes Manager an Employee that inherits its fields and methods.
    • A subclass constructor calls super(...) first, so the parent can set up the fields it owns.
    • A private field belongs to the class that declares it. The subclass gets that data through the parent's methods, here super.pay().
    • Overriding changes one method for the subclass and leaves the rest as inherited.
    • Inherited code that calls this.pay() picks up the override, so describe needs no second copy.

    Design the parent so that its methods call each other through this, and the subclasses can change behavior by overriding a single method.

    Keep going with TypeScript500+ step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free