Understanding TypeScript's private

TypeScript is a structural type system. When we compare two different types, regardless of where they came from, if the types of all members are compatible, then we say the types themselves are compatible.
However, when comparing types that have private and protected members, we treat these types differently. For two types to be considered compatible, if one of the them has a private member, then the other must have a private member that originated in the same declaration. The same applies to protected members.
class Animal { private name: string; constructor( theName: string ) { this.name = theName; } } class Rhino extends Animal { constructor() { super( 'Rhino' ); } } class Employee { private name: string; constructor( theName: string ) { this.name = theName; } } let animal = new Animal( 'Goat' ); let rhino = new Rhino(); let employee = new Employee( 'Bob' ); animal = rhino; // Type 'Employee' is not assignable to type 'Animal'. // Types have separate declarations of a private property 'name'. animal = employee;

Understanding protected

The protected modifier acts much like the private modifier with the exception that members declared protected can also be accessed within deriving classes.
A constructor may also be marked protected. This means that the class cannot be instantiated outside of its containing class, but can be extended.

Readonly modifier

You can make properties readonly by using the readonly keyword. Readonly properties must be initialized at their declaration or in the constructor.
class Octopus { readonly options: Record<string, string>; constructor() { this.options = {} } } let dad = new Octopus(); dad.options.name = 'Achilles';

Parameter properties

class Octopus { constructor( readonly name: string, private age?: number ){} } new Octopus( 'Achilles' ); new Octopus( 'Achilles', 30 );


Accessors with a get and no set are automatically inferred to be readonly. This is helpful when generating a .d.ts file from your code, because users of your property can see that they can't change it.

Abstract Classes

Abstract classes are base classes from which other classes may be derived. They may not be instantiated directly. Unlike an interface, an abstract class may contain implementation details for its members. The abstract keyword i used to define abstract classes as well as abstract methods within an abstract class.
abstract class Animal { abstract makeSound(): void; move(): void { console.log( 'roaming the earth...' ); } }

Constructor functions

When you declare a class in TypeScript, you are actually creating multiple declarations at the same time.
  1. The type of the instance of the class
  1. The constructor function.

typeof [constructor]

import Controller from './controller'; export type YnnOptions = { controllers?: Record<string, typeof Controller>; } export default class Ynn extends Koa { controllers: Record<string, typeof Controller>; constructor( options: YnnOptions = {} ) { super(); this.controllers = options.controllers || {}; } }

{ new(): any }

class Controller {} class Provider { constructor( public options: Record<string, any> ) {} } type YnnOptions = { controllers: Record<string, typeof Controller>; providers: Record<string, { new(): any }>; } const options: YnnOptions = { controllers : { index : Controller, }, providers : { // Type 'typeof Provider' is not assignable to type 'new () => any'. user : Provider } }

Using a class as an interface

As we said in the previous section, a class declaration creates two things: a type representing instances of the class and a constructor function. Because classes create types, you can use them in the same places you would be able to use interfaces.
class Point { x: number; y: number; } interface Point3d extends Point { z: number; } let point3d: Point3d = { x : 1, y : 2, z : 3 };

Create a class with a constructor function

function Bird() { } Bird.prototype.fly = function() { } // 'new' expression, whose target lacks a construct signature, implicitly has an 'any' type.(7009) const bird = new Bird();
Declare the Bird class before creating it.
declare class Bird { fly: () => void; } function Bird() { } Bird.prototype.fly = function() { } const bird = new Bird();
Using type assertions
function Bird() { } Bird.prototype.fly = function() { } const bird = new ( Bird as unknown as { new (): any } )();