# Classes
TIP
Welcome to CLASS chapter!
TypeScript adds type annotations
and other syntax
to allow you to express relationships between classes and other types
Getters / Setters
implements
extends
public
protected
private
Static
abstract
class Point {
readonly name: string = "world";
x: number;
y: number;
}
const pt = new Point();
pt.x = 0;
pt.y = 0;
strictPropertyInitialization
settingOFF/ON
- controls whether class fields
need
to beinitialized
in theconstructor
- controls whether class fields
class GoodGreeter {
name: string;
constructor() {
this.name = "hello"; // initialized
}
}
# Super Calls
- if you have a
base
class, you’ll need to callsuper()
in yourconstructor
body before using any this. members
class Base {
k = 4;
}
class Derived extends Base {
constructor() {
super(); // before everything
console.log(this.k);
}
}
# Accessors
class C {
_length = 0;
get length() {
return this._length;
}
set length(value) {
this._length = value;
}
- some special inference
rules
- If
get
exists but noset
, the property is automaticallyreadonly
- If the type of the
setter
parameter isnot
specified, it isinferred
from thereturn
type of thegetter
Getters
andsetters
must have thesame
Member Visibility
- If
# Member Visibility
public
protected
private
- control whether certain methods or properties are
visible
to code outside the class
public
- default
- can be accessed anywhere
- you
don’t
ever need to write it on a class member, but might choose to do so forstyle/readability reasons
( let's sb know exactly )
protected
- only visible to
subclasses
of the class they’re declared in - we need to be
careful
torepeat
theprotected
modifier if this exposure isn’t intentional.
- only visible to
class f {
public greet(){}
protected getName() {return "hi";}
}
class p extends f {
public howdy() {
console.log("Howdy, " + this.getName()); // from class f
}
}
const g = new p();
g.greet(); // OK
g.getName(); // error
// ----
class Base {
protected x: number = 1;
}
class Derived1 extends Base {
protected x: number = 5;
}
class Derived2 extends Base {
f1(other: Base) {
other.x = 10; // error
}
f2(other: Derived1) {
other.x = 10; // error
}
f3(other: Derived2) {
other.x = 10;
}
}
private
doesn’t
allow access to the membereven
fromsubclasses
- some policy
private
andprotected
are only enforced duringtype checking
(means in js file thoes modifies aren't working ... )private
also allows access using["bracket notation"]
during type checking- If you need to
protect
values in your class from malicious actors, you should use mechanisms that offerhard
runtime privacy, such asclosures
,WeakMaps
, orprivate
fields. Note that these added privacy checks during runtime couldaffect
performance.
# Index Signatures
- NOTE that it’s
better
to store indexed data inanother
place instead of on the class instance itself
class MyClass {
[s: string]: boolean | ((s: string) => boolean);
check(s: string) {
return this[s] as boolean;
}
}
# Class Heritage
implements
extends
super
- Like other languages with object-oriented features, classes in JavaScript can inherit from base classes
implements
- it's only a
check
that the class can be treated as theinterface
type. Itdoesn’t
change the type of the class or its methodsat all
implementing
aninterface
with an optional propertydoesn’t
create that property
- it's only a
interface A {
x: number;
y?: number;
check(name: string): boolean;
}
class C implements A {
x = 0;
check(s) {
return s.toLowercse() === "ok"; // Notice no error here
}
}
const c = new C();
c.y = 10; // error
extends
- Classes may extend from a base class. A derived class has
all
theproperties
andmethods
of its base class, and also defineadditional
members - A derived class can also
override
a base class field or property, note that it not simply repeat a method but usesuper.
- Classes may extend from a base class. A derived class has
- remember that JavaScript classes are a simple
lookup
object, looking up like a chain
class Base {
greet() {
console.log("Hello, world!");
}
}
class Derived extends Base {
greet(name?: string) { // name must optional
if (name === undefined) {
super.greet(); // override
} else {
console.log(`Hello, ${name.toUpperCase()}`);
}
}
}
const d = new Derived();
d.greet(); // Hello, world!
d.greet("reader"); // Hello, reader
# Static Members
- NOTE:
NO
Static Classes,only
members - static members
aren’t
associated with a particularinstance
of the class. They can beaccessed
through the classconstructor
object itself ( means you can access those fieldswithout
creating an instance of the class) - static members can
also
use the samepublic
,protected
, andprivate
visibility modifiers
class MyClass {
static x = 0;
static printX() {
console.log(MyClass.x);
}
}
console.log(MyClass.x);
MyClass.printX();
Function
properties likename
,length
, andcall
aren’t valid to define as static members
class S {
static name = "S!"; // error
// Static property 'name' conflicts with built-in property 'Function.name' of constructor function 'S'
}
- static Blocks
- we can write
initialization
code with all the capabilities of writing static Blocks
- we can write
class Foo {
static #count = 0;
get count() {
return Foo.#count;
}
static {
try {
...
}
catch {}
}
}
# Generic Classes
class Box<Type> {
contents: Type;
constructor(value: Type) {
this.contents = value;
}
}
//const b: Box<string>
const b = new Box("hello!");
# this
- the value of
this
inside a function depends on how the function wascalled
class MyClass {
name = "MyClass";
getName() {
return this.name;
}
}
const c = new MyClass();
const obj = { // the function was called through the `obj` reference
name: "obj",
getName: c.getName,
};
console.log(obj.getName()); // "ojb"
- TypeScript provides some ways to
mitigate
orprevent
this kind of error
Arrow Functions
- when a function that will
often
be called in a way thatloses
its this context
- when a function that will
class MyClass {
name = "MyClass";
getName = () => { // arrow func
return this.name;
};
}
const c = new MyClass();
console.log(c.getName()); // "MyClass"
this
asparameters
- an add a
this
parameter to methoddefinitions
to staticallyenforce
that the method is calledcorrectly
- an add a
class MyClass {
name = "MyClass";
getName(this: MyClass) {
return this.name;
}
}
const c = new MyClass();
c.getName();// OK
const g = c.getName;
console.log(g());// Error
this
asTypes
- a special type called
this
refersdynamically
to the type of the current class
- a special type called
class Box {
...
set(value: string) {
...
return this;
}
}
# Parameter Properties
public
private
protected
readonly
- special syntax for turning a
constructor
parameter into a class property with the same name and value
class Params {
constructor(
public readonly x: number,
protected y: number,
private z: number
) {
// No body necessary
}
}
const a = new Params(1, 2, 3);
console.log(a.x);
# abstract Classes and Members
abstract
- An abstract
method
or abstractfield
is one that hasn’t had animplementation
provided. These membersmust
exist inside an abstract class, whichcannot
be directlyinstantiated
abstract class Base {
abstract getName(): string;
printName() {
console.log(this.getName())
}
}
const b = new Base();// error
class t extends Base {
getName() { //can't forget this
return "world";
}
}
const d = new t();
d.printName();// "world"
- Sometimes you want to
accept
some class constructor function that produces aninstance
of a class whichderives
from some abstract class
abstract class Base {
abstract getName(): string;
printName() {}
}
class Derived extends Base {
getName() {
return "";
}
}
// ---cut---
function greet(ctor: new () => Base) {
const instance = new ctor();
instance.printName();
}
greet(Derived);// it's concrete
greet(Base); //error, because it's abstract