Published on

Functionality with Classes

1999 words10 min read
Authors
  • avatar
    Name
    Curtis Warcup
    Twitter

What are classes?

Definition: class is a blueprint/model to create an object with some fields (values) and methods (functions) to represent a 'thing'.

  • use class keyword, then write the name of the class with a capital.
  • we are creating a blueprint for what a Vehicle should be. We are not actually calling these methods directly.
class Vehicle {
  drive(): void {
    console.log('chugga chugga')
  }
}

const vehicle = new Vehicle()

Now with a new instance of a class, we have access to all the methods in that class.

//define a new class

class Vehicle {
  drive(): void {
    console.log('chugga chugga')
  }
  honk(): void {
    console.log('beep beep!')
  }
}

const vehicle = new Vehicle()

vehicle.drive() // chugga chugga
vehicle.honk() // beep beep!

Inheritance

Lets make a new class called "Car". Everything a car can do, a vehicle should be able to do.

  • we could either copy all the properties of the 'Vehicle'...
  • or we can write extends to extend the properties to Car
    • tells TS to copy all the properties from Vehicle into Car
class Vehicle {
  drive(): void {
    console.log('chugga chugga')
  }
  honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {}

const car = new Car()
car.drive() // chugga chugga
car.honk() // beep beep!

we can also redefine a property to override the parent property.

class Vehicle {
  drive(): void {
    console.log('chugga chugga')
  }
  honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {
  drive(): void {
    console.log('vroom!')
  }
}

const car = new Car()
car.drive() //vroom!
car.honk() // beep beep!

Instance Method Modifiers

Modifiers are a keyword we can can place on different methods and properties in a class.

  • can be either public, private or protected

If you do not add any modifier, TS defaults to public.

Examples:

class Vehicle {
  public drive(): void {
    console.log('chugga chugga')
  }
  public honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {
  public drive(): void {
    console.log('vroom!')
  }
}

const car = new Car()
car.drive()
car.honk()

No change. Will act the exact same as previously. Private Modifier

class Vehicle {
  public drive(): void {
    console.log('chugga chugga')
  }
  public honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {
  private drive(): void {
    console.log('vroom!')
  }
}

const car = new Car()
car.drive()
car.honk()

get an error on car.drive() "Property 'drive' is private and only accessible within class 'Car'."

Can add a new function called startDrivingProcesses() and call the drive() function in it.

class Vehicle {
  public drive(): void {
    console.log('chugga chugga')
  }
  public honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {
  private drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
  }
}

const car = new Car()
car.startDrivingProcess() // vroom!
car.honk() // beep beep!

Why do we care?

  • we do not mark something as private for security.
  • use it to limit developers to prevent them from calling a method.

Protected Modifiers:

class Vehicle {
  protected honk(): void {
    console.log('beep beep!')
  }
}

class Car extends Vehicle {
  drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
    this.honk()
  }
}

const car = new Car()
car.startDrivingProcess() // will work because this.honk() is called inside the class
car.honk() //will NOT work since it is called outside the class

Fields in Classes

class Vehicle {
  color: string = 'red' // initialize a variable inside a class

  protected honk(): void {
    console.log('beep beep!')
  }
}

const vehicle = new Vehicle()
console.log(vehicle.color) // red

But what is we want to write something like const vehicle = new Vehicle('orange'); and have that be the color? In this case, we need a constructor.

class Vehicle {
  color: string = 'red'

  constructor(color: string) {
    this.color = color
  }

  protected honk(): void {
    console.log('beep beep!')
  }
}

const vehicle = new Vehicle('orange')
console.log(vehicle.color) // orange

can either initialize a property using the default value, or use the constructor and add an argument.

Shortcut to automate this:

  • delete the implementation inside the constructor, delete the property definition...
  • and add public to the constructor.
class Vehicle {
  constructor(public color: string) {}

  protected honk(): void {
    console.log('beep beep!')
  }
}

const vehicle = new Vehicle('orange')
console.log(vehicle.color)

this code is equivalent to the previous example. This is just shorter.

Fields with Inheritance

class Vehicle {
  constructor(public color: string) {}

  protected honk(): void {
    console.log('beep beep!')
  }
}

const vehicle = new Vehicle('orange')

class Car extends Vehicle {
  drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
    this.honk()
  }
}

const car = new Car() // get an error here

error: constructor Car(color: string): Car. Expected 1 arguments, but got 0.

We need to provide an argument: const car = new Car('red');

Now whenever we create a new instance of Car, because Car extends from Vehicle, Car expects an argument for the constructor. This is because Vehicle is the parent.

Things will be a little different if we define a constructor function inside Car as well.

class Car extends Vehicle {
  constructor(public wheels: number) {
    // get an error here
  }
  drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
    this.honk()
  }
}

Error: constructor Car(wheels: number): Car Constructors for derived classes must contain a 'super' call.

What is super ?

  • is a reference to the 'super' class, or parent class of car which is Vehicle
    • we must also call the super constructor of the parent as well.
class Car extends Vehicle {
  constructor(public wheels: number) {
    super('red')
  }
  drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
    this.honk()
  }
}

but chances are we still want the color to come in as an argument when we create it. How do we do this?

class Car extends Vehicle {
  constructor(public wheels: number, color: string) {
    super(color)
  }
  drive(): void {
    console.log('vroom!')
  }
  startDrivingProcess(): void {
    this.drive()
    this.honk()
  }
}

const car = new Car(4, 'red')
console.log(car) // { color: 'red', wheels: 4 }

Where to Use Classes

  • remember interfaces and classes are the primary tools in typescript.
  • when we use TS, we have a single file for each class.
    • and use these different classes through the use of interfaces.