class
Let's see the use of classes
class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return "Hello, " + this.greeting; } } let greeter = new Greeter("world");
There are three parts: a property called greeting, a constructor, and a greet method.
inherit
class Animal { name:string constructor(theName:string){ this.name = theName } move(distanceInMeters:number = 0){ console.log(`${this.name} moved ${distanceInMeters}.`) } } class Snake extends Animal { constructor(name:string){ super(name) } move(distanceInMeters = 5){ console.log("Slithering...") super.move(distanceInMeters) //Call the move method of the parent class } } class Horse extends Animal { constructor(name:string){ super(name) } move(distanceInMeters = 45){ console.log("Galloping...") super.move(distanceInMeters) } } let sam = New Snake("Sammy the Python") let tom:Animal = new Horse("Tommy the Palomino") sam.move() tom.move(34)
A derived class contains a constructor that must call super(), which executes the constructor of the base class.
If you want to access this property in the constructor, you must first call super()
At the same time, this example rewrites the move method
//Print results Slithering... Sammy the Python moved 5m. Galloping... Tommy the Palomino moved 34m.
Public, private and protected modifiers
public
In TypeScript, members default to public.
You can write it like this
class Animal { public name: string; public constructor(theName: string) { this.name = theName; } public move(distanceInMeters: number) { console.log(`${this.name} moved ${distanceInMeters}m.`); } }
private
When a member is marked private, it cannot be accessed outside the class that declares it
class Animal { private name: string; constructor(theName: string) { this.name = theName; } } new Animal("Cat").name; // Error: 'name' is private
protected
The protected modifier behaves much like the private modifier, but the protected member is still accessible in the derived class.
class Person { protected name: string; constructor(name: string) { this.name = name; } } class Employee extends Person { private department: string; constructor(name: string, department: string) { super(name) this.department = department; } public getElevatorPitch() { return `Hello, my name is ${this.name} and I work in ${this.department}.`; } } let howard = new Employee("Howard", "Sales"); console.log(howard.getElevatorPitch()); console.log(howard.name); // error
The constructor can also be marked protected. Then this class can be inherited, but cannot be instantiated.
class Person { protected name: string; protected constructor(theName: string) { this.name = theName; } } // Employee can inherit Person class Employee extends Person { private department: string; constructor(name: string, department: string) { super(name); this.department = department; } public getElevatorPitch() { return `Hello, my name is ${this.name} and I work in ${this.department}.`; } } let howard = new Employee("Howard", "Sales"); let john = new Person("John"); // Error: the constructor for 'Person' is protected
readonly modifier
class Octopus { readonly name: string; readonly numberOfLegs: number = 8; constructor (theName: string) { this.name = theName; } } let dad = new Octopus("Man with the 8 strong legs"); dad.name = "Man with the 3-piece suit"; // Error! name is read-only
Parameter properties
Use parameter attributes to modify the previous paragraph. As follows:
class Octopus { readonly numberOfLegs: number = 8; constructor(readonly name: string) { } }
Parameter properties are declared by adding an access qualifier to the front of the constructor parameter. Using private to qualify a parameter property declares and initializes a private member; the same is true for public and protected.
Accessor
Code without accessor
class Employee { fullName: string; } let employee = new Employee(); employee.fullName = "Bob Smith"; if (employee.fullName) { console.log(employee.fullName); }
set method and get method
let passcode = "secret passcode"; class Employee { private _fullName: string; get fullName(): string { return this._fullName; } set fullName(newName: string) { if (passcode && passcode == "secret passcode") { this._fullName = newName; } else { console.log("Error: Unauthorized update of employee!"); } } } let employee = new Employee(); employee.fullName = "Bob Smith"; if (employee.fullName) { alert(employee.fullName); }
Note that accessors with only get and no set are automatically inferred as readonly.
Static properties
Static properties exist only on the class, not on the instance of the class.
class Grid { static origin = { x: 0, y: 0 }; calculateDistanceFromOrigin(point: { x: number; y: number }) { let xDist = point.x - Grid.origin.x; let yDist = point.y - Grid.origin.y; return Math.sqrt(xDist * xDist + yDist * yDist) / this.scale; } constructor(public scale: number) {} } let grid1 = new Grid(1.0); // 1x scale let grid2 = new Grid(5.0); // 5x scale console.log(grid1.calculateDistanceFromOrigin({ x: 10, y: 10 })); console.log(grid2.calculateDistanceFromOrigin({ x: 10, y: 10 }));
Use static to define origin, because it is an attribute used by all grids. When each instance wants to access this property, it needs to add the class name before the origin. Grid. To access static properties.
abstract class
Abstract classes are used as base classes of other derived classes. They are generally not instantiated directly.
abstract class Animal { abstract makeSound(): void; move(): void { console.log("roaming the earch..."); } }
Abstract methods in abstract classes do not contain concrete implementations and must be implemented in derived classes. The syntax of an abstract method is similar to that of an interface method. Both define method signature but do not include method body. However, an abstract method must contain the abstract keyword and can contain access modifiers.
abstract class Department { constructor(public name: string) {} printName(): void { console.log("Department name: " + this.name); } abstract printMeeting(): void; // Must be implemented in a derived class } class AccountingDepartment extends Department { constructor() { super("Accounting and Auditing"); // super() must be called in the constructor of a derived class } printMeeting(): void { console.log("The Accounting Department meets each Monday at 10am."); } generateReports(): void { console.log("Generating accounting reports..."); } } let department: Department; // Allow to create a reference to an abstract type department = new Department(); // Error: cannot create an instance of an abstract class department = new AccountingDepartment(); // Allow instantiation and assignment of an abstract subclass department.printName(); department.printMeeting(); department.generateReports(); // Error: method does not exist in the declared abstract class
Advanced skills
Constructor
// ts writing class Greeter { greeting: string; constructor(message: string) { this.greeting = message; } greet() { return 'Hello, ' + this.greeting; } } let greeter: Greeter; greeter = new Greeter('world'); console.log(greeter.greet()); // Previous paragraph changed to JS let Greeter = (function() { function Greeter(message) { this.greeting = message; } Greeter.prototype.greet = function() { return 'Hello, ' + this.greeting; }; return Greeter; })(); let greeter; greeter = new Greeter('world'); console.log(greeter.greet());
We can think of a class as having two parts: the instance part and the static part.
Let's rewrite this example a little to see the difference between them:
class Greeter { static standardGreeting = 'Hello, there'; greeting: string; greet() { if (this.greeting) { return 'Hello, ' + this.greeting; } else { return Greeter.standardGreeting; } } } let greeter1: Greeter; greeter1 = new Greeter(); console.log(greeter1.greet()); let greeterMaker: typeof Greeter = Greeter; greeterMaker.standardGreeting = 'Hey there!'; let greeter2: Greeter = new greeterMaker(); console.log(greeter2.greet());
Using classes as interfaces
class Point { x: number; y: number; } interface Point3d extends Point { z: number; } let point3d: Point3d = {x: 1, y: 2, z: 3};