Skip to content

Abstract Classes

Video Lecture

Section Video Links
Abstract Classes Abstract Classes Abstract Classes 

Overview

Abstract classes are like a mixture of implementing interfaces and extending a class in one step. You can create a class with optional methods and properties, but also indicate which methods and properties must be implemented in the derived class. Note that your base class, despite enforcing abstract rules, is still able to itself implement any interfaces you desire.

Use the abstract keyword to indicate a class contains abstract methods or properties.

Abstract Class Example 1

In this first example, the abstract class Animal has an abstract property name. Cat and Dog must implement the property name themselves rather than inherit from the base class.

Note that the abstract name in the Animal class definition cannot be initialized a value in either the class attribute definition or in its constructor. It is now a rule indicating that name must be initialized by the derived class instead.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
abstract class Animal {
    abstract name: string
    age: number

    constructor(age: number) {
        //this.name = name // this must now be assigned in the derived class instead
        this.age = age
    }

    feed(food: string, amount: number): void {
        console.log(
            'Feeding ' +
                this.name +
                ' the ' +
                this.constructor.name +
                ' ' +
                amount +
                ' kg of ' +
                food
        )
    }
}

class Cat extends Animal {
    name: string
    constructor(name: string, age: number) {
        super(age)
        this.name = name
    }
}

class Dog extends Animal {
    name: string
    constructor(name: string, age: number) {
        super(age)
        this.name = name
    }
}

const CAT = new Cat('Cosmo', 8)
const DOG = new Dog('Rusty', 12)
CAT.feed('Fish', 0.1)
DOG.feed('Beef', 0.25)

Replace ./src/test.ts with this code above, compile and execute it.

tsc -p ./src
node ./dist/test.js

Outputs

Feeding Cosmo the Cat, 0.1kg of Fish
Feeding Rusty the Dog, 0.25kg of Beef

Also note that classes marked as abstract cannot be directly instantiated. I.e.,

//const CAT = new Cat('Cosmo', 8)
const CAT = new Animal('Cosmo', 8)

will indicate an error

Cannot create an instance of an abstract class

Abstract Class Example 2

If any methods are marked as abstract, then they must also be implemented in the derived class.

Methods marked as abstract in the base class, do not contain a body. The body will be implemented by the derived class instead.

Also note that in the following example, age has been set as a default to be -1. Setting a default value is optional.

So, if you want the functionality offered of an interface, i.e., the rules, but you also want your interface to potentially have default or optional properties and/or methods, then you can use an abstract class instead. Don't forget the use of super in the derived classes' constructor so that the default or optional properties and methods are initialized.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
abstract class Animal {
    abstract name: string
    age = -1

    constructor() {}

    abstract feed(food: string, amount: number): void
}

class Cat extends Animal {
    name: string
    constructor(name: string, age: number) {
        super()
        this.name = name
        this.age = age
    }

    feed(food: string, amount: number): void {
        console.log(
            'Feeding ' +
                this.name +
                ' the Cat ' +
                amount +
                ' kg of ' +
                food
        )
    }
}

class Dog extends Animal {
    name: string
    constructor(name: string, age: number) {
        super()
        this.name = name
        this.age = age
    }

    feed(food: string, amount: number): void {
        console.log(
            'Feeding ' +
                this.name +
                ' the Dog ' +
                amount +
                ' kg of ' +
                food
        )
    }
}

const CAT = new Cat('Cosmo', 8)
const DOG = new Dog('Rusty', 12)
CAT.feed('Fish', 0.1)
DOG.feed('Beef', 0.25)

Replace ./src/test.ts with this code above, compile and execute it.

tsc -p ./src
node ./dist/test.js

Outputs

Feeding Cosmo the Cat, 0.1kg of Fish
Feeding Rusty the Dog, 0.25kg of Beef