DEV Community

Cover image for Ts - Classes
adasd
adasd

Posted on • Edited on

Ts - Classes

class Point {}
Enter fullscreen mode Exit fullscreen mode

➡️Class fields

A field declaration creates a public writeable property on a class:

class Point {
x: number;
y: number;
}
const pt = new Point();
pt.x = 0;
pt.y = 0;
Enter fullscreen mode Exit fullscreen mode

As with other locations, the type annotation is optional, but will be an implicit any if not specified.
Fields can also have initializers; these will run automatically when the class is instantiated:

class Point {
x = 0;
y = 0;

}
const pt = new Point();
// Prints 0, 0
console.log(`${pt.x}, ${pt.y}`);
Enter fullscreen mode Exit fullscreen mode

Just like with const, let, and var, the initializer of a class property will be used to infer its type:

const pt = new Point();
pt.x = "0"; //Error ==> Type 'string' is 
//not assignable to type 'number'.
Enter fullscreen mode Exit fullscreen mode

🔵 read-only fields

Fields may be prefixed with the readonly modifier. This prevents assignments to the field outside of the constructor.

class Greeter {

readonly name: string = "world";
    constructor(otherName?: string) {
    if (otherName !== undefined) {
        this.name = otherName;
        }
    }
    err() {
    this.name = "not ok"; //Cannot assign to 
    //'name' because it is a read-only property.
    }
}

const g = new Greeter();
g.name = "also not ok"; //Error - 
//Cannot assign to 'name' because it is a read-only property.
Enter fullscreen mode Exit fullscreen mode

➡️ Constructors

Class constructors are very similar to functions. You can add parameters with type annotations, default values, and overloads:

class Point {
x: number;
y: number;
// Normal signature with defaults
    constructor(x = 0, y = 0) {
    this.x = x;

    this.y = y;
    }
}
Enter fullscreen mode Exit fullscreen mode

There are just a few differences between class constructor signatures and function signatures:

  • Constructors can’t have type parameters - these belong on the outer class declaration, which we’ll learn about later
class Point{
constructor(val:T) //Error Type T is not defined
    {
    }
}
class Point<T>{
constructor(val:T) //Ok
    {
    }
}
const point = new Point<number>(10)
Enter fullscreen mode Exit fullscreen mode
  • Constructors can’t have return type annotations - the class instance type is always what’s returned.
class Point{
    constructor():boolean //Error - Type annotation 
    //cannot appear on a constructor declaration
    {
    }
}
Enter fullscreen mode Exit fullscreen mode

➡️ Methods

A function property on a class is called a method. Methods can use all the same type annotations as functions and constructors:

class Point {
x = 10;
y = 10;
    scale(n: number): void {
    this.x *= n;
    this.y *= n;

    }
}
Enter fullscreen mode Exit fullscreen mode

Note that inside a method body, it is still mandatory to access fields and other methods via this

let x: number = 0;

class C {
x: string = "hello";
    m() {
    // This is trying to modify 'x' from line 1, not the class property
    x = "world";
    }
}
Enter fullscreen mode Exit fullscreen mode

➡️ Class Heritage

🔵 implements Clauses

You can use an implements clause to check that a class satisfies a particular interface. An error will be issued if a class fails to correctly implement it:

interface Pingable {
ping(): void;
}

class Sonar implements Pingable {
    ping() {
    console.log("ping!");
    }
}

class Ball implements Pingable {   //Error - Class 'Ball' incorrectly 
//implements interface 'Pingable'. Property 'ping' is missing 
//in type 'Ball' but required in type 'Pingable'.
    pong() {
    console.log("pong!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Classes may also implement multiple interfaces, e.g. class C implements A, B {.

🚨 caution -

It’s important to understand that an implements clause is only a check that the class can be treated as the interface type. It doesn’t change the type of the class or its methods at all. A common source of error is to assume that an implements clause will change the class type - it doesn’t!

interface Checkable {
check(name: string): boolean;
}

class NameChecker implements Checkable {
    check(s) { //warning ==> Parameter 's' implicitly has an 'any' type.
    // Notice no error here because type is 'any'
    return s.toLowerCase() === "ok";

    }

}
Enter fullscreen mode Exit fullscreen mode

In this example, we perhaps expected that  s’s type would be influenced by the name: string parameter of check. It is not - implements clauses don’t change how the class body is checked or its type inferred.
similarly, implementing an interface with an optional property doesn’t create that property:

interface A {
x: number;
y?: number;
}

class C implements A {
x = 0;
}

const c = new C();

c.y = 10;
Enter fullscreen mode Exit fullscreen mode

🔵 extends Clauses

Classes may extend from a base class. A derived class has all the properties and methods of its base class, and can also define additional members.

class Animal {
    move() {
    console.log("Moving along!");
    }
}

class Dog extends Animal {
    woof(times: number) {
    for (let i = 0; i < times; i++) {
    console.log("woof!");
        }
    }
}
const d = new Dog();
// Base class method
d.move();
// Derived class method
d.woof(3);
Enter fullscreen mode Exit fullscreen mode

➡️ Member Visibility

🔵public

The default visibility of class members is public. A public member can be accessed anywhere:

class Greeter {
    public greet() {
    console.log("hi!");
    }
}
const g = new Greeter();
g.greet();
Enter fullscreen mode Exit fullscreen mode

Because public is already the default visibility modifier, you don’t ever need to write it on a class member, but might choose to do so for style/readability reasons.

🔵protected

protected members are only visible to subclasses of the class they’re declared in.

class Greeter {
    public greet() {
    console.log("Hello, " + this.getName());
    }
    protected getName() {
    return "hi";
    }
}

class SpecialGreeter extends Greeter {
    public howdy() {
    // OK to access protected member here
    console.log("Howdy, " + this.getName());
    }
}
const g = new SpecialGreeter();
g.greet(); // OK
g.getName(); //Error - Property 'getName' is protected and only 
//accessible within class 'Greeter' and its subclasses.
Enter fullscreen mode Exit fullscreen mode

🔵sibling protected members

TypeScript doesn’t allow accessing protected members of a sibling class in a class hierarchy:

class Base {
protected x: number = 1;
}

class Derived1 extends Base {
protected x: number = 5;
}

class Derived2 extends Base {
    f1(other: Derived2) {
    other.x = 10;

    }
    f2(other: Derived1) {
        other.x = 10; //Error - Property 'x' is protected 
        //and only accessible within class 'Derived1' and its subclasses.
    }

}
Enter fullscreen mode Exit fullscreen mode

🔵private

private is like protected , but doesn’t allow access to the member even from subclasses:

class Base {
private x = 0;
}
const b = new Base();
// Can't access from outside the class
console.log(b.x);  // Error -Property 'x' is private and 
//only accessible within class 'Base'.
Enter fullscreen mode Exit fullscreen mode

🚨 Caveats

Typescript private and protected access modifiers only exists in typescript not in JavaScript. meaning that if you run the script with access error the script will run ok.

class A{
private sayHi()
    {
    console.log("private method");
    }
}

const a = new A();
//during compilation error occurs
a.sayHi(); // Error - Property sayHi is private and only 
//accessible within class 'A'.
//But if we execute the file  it gives below output -
//private method
Enter fullscreen mode Exit fullscreen mode

🚨 JavaScript supports private access modifier but syntax is different from those of TypeScript.

class A{
#sayHi()
    {
    console.log("private method");
    }
}

const a = new A();
a.sayHi(); //Error -  a.sayHi is not a function
Enter fullscreen mode Exit fullscreen mode

🚨 You can access the private members of class outside of the class with bracket [ ] syntax

class A{
private sceret = "Hello"
}

const a = new A();
a["sceret"]; // Hello
Enter fullscreen mode Exit fullscreen mode

➡️ Static Fields and methods

Classes may have static members. These members aren’t associated with a particular instance of the class. They can be accessed through the class constructor object itself:

class MyClass {
    static x = 0;
    static printX() {
    console.log(MyClass.x);
    }
}
console.log(MyClass.x);
MyClass.printX();
Enter fullscreen mode Exit fullscreen mode

Static members can also use the same public, protected, and private visibility modifiers:

class MyClass {
private static x = 0;
}
console.log(MyClass.x); //Error - Property 'x' is private 
//and only accessible within class 'MyClass'.
Enter fullscreen mode Exit fullscreen mode

Static members are also inherited:

class Base {
    static getGreeting() {
    return "Hello world";
    }
}

class Derived extends Base {
    myGreeting = Derived.getGreeting(); //Hello world
}
Enter fullscreen mode Exit fullscreen mode

➡️ Generic Classes

Classes, much like interfaces, can be generic. When a generic class is instantiated with new, its type parameters are inferred the same way as in a function call:

class Box<Type> {
    contents: Type;
    constructor(value: Type) {
    this.contents = value;
    }
}
const b = new Box("hello!"); //Infered as   const b: Box<string>
Enter fullscreen mode Exit fullscreen mode

Type Parameters in Static Members

type parameters does ❌ not supported in static methods

class Box<Type> {
static defaultValue: Type; //Error -Static members cannot 
//reference class type parameters.
}
Enter fullscreen mode Exit fullscreen mode

➡️ Parameter Properties

TypeScript offers special syntax for turning a constructor parameter into a class property with the same name and value. These are called parameter properties and are created by prefixing a constructor argument with one of the visibility modifiers public, private, protected, or read-only. The resulting field gets those modifier(s):

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); //1
console.log(a.z);  //Error -Property 'z' is private 
//and only accessible within class 'Params'.
Enter fullscreen mode Exit fullscreen mode

➡️ abstract Classes and Members

Classes, methods, and fields in TypeScript may be abstract.
An abstract method or abstract field is one that hasn’t had an implementation provided. These members must exist inside an abstract class, which cannot be directly instantiated.

The role of abstract classes is to serve as a base class for subclasses which do implement all the abstract members. When a class doesn’t have any abstract members, it is said to be concrete.

abstract class Base {
    abstract getName(): string;
    printName() {
    console.log("Hello, " + this.getName());
    }
}
const b = new Base(); //Error - Cannot create 
//an instance of an abstract class.
Enter fullscreen mode Exit fullscreen mode

We can’t instantiate Base with new because it’s abstract. Instead, we need to make a derived class and implement the abstract members:

class Derived extends Base {
    getName() {
    return "world";
    }
}
const d = new Derived();
d.printName();  //Ok
Enter fullscreen mode Exit fullscreen mode

Notice that if we forget to implement the base class’s abstract members, we’ll get an error:

class Derived extends Base {//Error - Non-abstract class 
//'Derived' does not implement inherited abstract member 
//getName from class 'Base'.
}
Enter fullscreen mode Exit fullscreen mode

🚨🚨 Things to note -

  1. abstract keyword used to mark a class abstract.
  2. only abstract classes can have abstract methods and fields. Normal classes cannot have theme.
  3. If a class is extends abstract class then it have to implement all the abstract methods and fields of that abstract class.

extends and implements in abstract classes

implements -

there is no ❌ use implements in a abstract classes as implements is a indication to implement the methods and properties of interface or type and that is against what abstract classes are about.
still use can use implements on a abstract class and then you have to compulsory declare those in a abstract class.

 class A {             
    hello;
    sayHi(){
       }
  }

abstract class B implements A{
  hello;
  sayHi:boolean;
  abstract sayBye():void
}```

Enter fullscreen mode Exit fullscreen mode

Top comments (26)

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
asda12131 profile image
adasd

YUJ

Collapse
 
asda12131 profile image
adasd

dfgfd

Collapse
 
asda12131 profile image
adasd

sefd

Thread Thread
 
asda12131 profile image
adasd

FGH

Thread Thread
 
asda12131 profile image
adasd

ui

Collapse
 
asda12131 profile image
adasd

T13

Collapse
 
asda12131 profile image
adasd

fsdf

Thread Thread
 
asda12131 profile image
adasd

WERT

Collapse
 
asda12131 profile image
adasd

dfgfd sfsdfsd

Collapse
 
asda12131 profile image
adasd

RGd

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
asda12131 profile image
adasd

sdfds

Collapse
 
asda12131 profile image
adasd

tyt

Thread Thread
 
Sloan, the sloth mascot
Comment deleted
 
asda12131 profile image
adasd

fdgdgfdfgdf

Collapse
 
asda12131 profile image
adasd

xvd

Collapse
 
asda12131 profile image
adasd

asasd

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
asda12131 profile image
adasd

RG

Collapse
 
asda12131 profile image
adasd

ERER

Thread Thread
 
asda12131 profile image
adasd

gv

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
asda12131 profile image
adasd

ty