33
loading...
This website collects cookies to deliver better user experience
properties
and what it can do methods
. A class is declared with the class
keyword followed by the name of the class and it's a good convention to always begin your class names with Uppercase for the first letter. A class can have any number of properties we see fit and any number of methods we also see fit. Every class can implement it's own custom Constructor
function that will define how instances of that class are created. If the class is inheriting from another class, the base class would just call it's parent's constructor function.class _Element {
constructor(){}
}
let hydrogen = new _Element()
_Element
which will define what an element should look like and what it can do. We proceeded to create an instance of that element hydrogen
by calling the new
keyword followed by the name of the class and we invoke it like a function. The constructor function defined on the class would run only once, creating a new instance of an Element. Our Element has no properties on the but we can add some properties in the constructor function and annotate the variable name with an access modifier that will determine who has access to that property. TypeScript will auto add any argument we annotate with an access modifier to a property on the class, this helps to keep our code short and clean.class _Element {
constructor(
private _name: string,
readonly atomicMass: number,
protected _symbol: string
){}
}
let hydrogen = new _Element('Hydrogen', 1, 'H')
hydrogen.atomicMass // 1
class _Element {
constructor(
private _name: string,
readonly atomicMass: number,
protected _symbol: string
){}
get name() {
return this._name
}
set name (name){
this._name = name
}
}
let hydrogen = new _Element('Hydrogen', 1, 'H')
hydrongen._symbol // Not okay
hydrogen.name = 'something else' // Okay
readonly
, we are saying that other parts of the code are going to be able to see the value but they can't change it. We can also use protected
, this is quite similar to private. For using getters the main property has to begin with an underscore _varName
while the getter/setter for that property will be the name of the property but without the underscore.is a
pattern. This will also give rise to polymorphism which we will discuss in a bit.// Extending with Parent's constructor function
class Molecule extends _Element {
}
let water = new Molecule('H2O', 18, 'Hydrogen Oxide');
water._symbol // NOT POSSIBLE private
water.name // 'Hydorgen'
water.name = 'Water'
// Extending with custom constructor function
class Molecule extends _Element {
constructor(
_name:string,
atomicMass: number,
_symbol: string,
public reactants: _Elements[]
) {
super(_name, atomicMass, _symbol)
}
getReactants(){
let reactants = this.reactants.map(el => {
el._name
})
return reactants.join(' ')
}
}
let hydrogen = new _Element('H', 2, 'Hydrogen');
let oxygen = new _Element('O', 16, 'Oxygen')
let Water = new Molecule('H20', 18, 'Water', [hydrogen, oxygen])
Water.getReactants() // Hydrogen Oxygen
class Automobiles {
constructor(private _wheels: number, private _type: string) {}
move() {
return `moving in it's own way`;
}
}
Automobiles
and define how it moves.class Car extends Automobiles {
constructor(private _wheels: number, private _type: string){}
move(){
return `This car is moving in it's own way`
}
}
let mercedes = new Car(4, 'sports car')
console.log(mercedes.move()) // This car is moving in it's own way
interface Person {
name:string,
age: number,
gender: string
}
type createPersonSignature = (name:string, age:number, gender:string) => Person;
let createPerson: createPersonSignature
let createAdmin: createPersonSignature
createPerson = (name:string, age: number, gender:string) => ({
name,
age,
gender,
admin: false
})
createAdmin = (name: string, age: number, gender: string) => {
console.log('creating admin')
return { name, age, gender, admin: true}
}
let sam = createPerson('sam', 30, 'male')
let superAdmin = createAdmin('super', 100, 'female')
interface Person {
name: string
age: number
}
let userOne: Person
let userTwo: Person
let makeName = (name:string) => name
userOne = {
name: 'sam',
age: Math.random()
}
userTwo = {
name: makeName('john'),
age: 25
}
interface AutomobileContract {
move: ()=> string,
}
class Car implements AutomobileContract {
constructor(private _wheels: number, private _type: string){}
move(){
return `This car is moving in it's own way`
}
}
implements
keyword and a class can implement more than one interface but on the flip side the class has to explicitly fulfill the terms of the contract. If we didn't have the move method on the car class it would show an error in our IDE. Even if we implemented the function and it didn't return a string there would still be an error in our IDE. // EXTENDING FROM A CLASS
class Book {
constructor(public title: string, public author:string){}
getTitle(){
return this.title
}
}
interface TextBookContract extends Book {
subject: string
}
let chemistryTextBook: TextBookContract;
chemistryTextBook = {
title: 'chemistry book',
author: 'John Doe',
subject: 'chemisty',
getTitle: function () {
return `${this.title}`
}
}
interface BookContract {
title: string;
pages: number;
author: string;
}
interface NovelContract extends BookContract {
genre: string;
}
interface TextBookContract extends BookContract {
subject: string;
}
let Book1: TextBookContract = {
title: "chemistry book",
pages: 380,
author: "John Doe",
subject: "Chemistry"
};
let Book2: NovelContract = {
title: "The Gods are not to blame",
pages: 120,
author: "Ola Rotimi",
genre: "Tragedy"
};
class Automobiles {
constructor(protected name: string, private _wheels: number, readonly _type: string) {}
move() {
return `moving in it's own way`;
}
}
interface BookContract {
title: string
author: string
}
class Library {
books: BookContract[] = []
constructor(private librarian: Librarian){}
addBook(title, author){
let book = this.librarian.newBook(title, author)
this.books.push(book)
}
}
class Librarian {
libraries: Library[] = []
constructor(){
this.libraries.push(new Library(this))
}
newBook(title: string, author: string){
return { title, author }
}
addBooktoLibraries(name, author){
for(let library of libraries){
library.addBook(name, author)
}
}
}
let superLibrarian = new Librarian()
superLibrarian.addBookToLibraries('The gods are not to blame', 'Ola Rotimi')
newBook
method on the librarian each time a new book is added. A library cannot bring a new book but a librarian can so we delegate the task of creating a new book to a library... That is rather than calling newBook
outside rather we call newBook
inside a library, each library can newBook
when required, while a librarian can coordinate library to create and add new books. The librarian is the wrapper while the library is the delegate.has a
to fit situations where it makes more sense to use than is a
. Drawing from our example above we can say that a library has a librarian.