TypeScript Classes for Beginners: constructor, #private, implements, abstract
November 6, 2026
Welcome to episode 23 of TypeScript from Zero, a series for complete beginners (no JavaScript needed). Welcome back to TypeScript from zero! Today: classes. A class is a blueprint for objects that have both data and behavior. We are in the shop project, with a new file called classes.ts. Every code block below is the exact code and output from the video, ready to copy.
- All episodes are in the TypeScript from Zero playlist.
- Versions used: Node.js 26.13.0, npm 11.20.0, TypeScript 7.0.2.
Setup
We start in the terminal and open the project in VS Code:
cd shop
touch src/classes.ts
code .1. Class
A class has fields, which hold data, and methods, which are functions. This counter has a count that starts at zero, and a method increment. The word new creates an object from the blueprint. We increment twice, and the count is two.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);$ node src/classes.ts
22. Constructor
A constructor runs when we write new, and it sets up the object. This account has an owner, set in the constructor, and a balance. The hash sign makes the balance truly private. Only code inside the class can touch it. A getter lets everybody read it, without changing it.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);$ node src/classes.ts
2
Mia 503. Private
Now we try to read the private balance from outside. tsc refuses: property balance is not accessible outside the class, because it has a private identifier. TS18013. Node refuses too, and does not even start the program.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);
console.log(acc.#balance);$ node src/classes.ts
file:///home/mah/shop/src/classes.ts:27
console.log(acc.#balance);
^
SyntaxError: Private field '#balance' must be declared in an enclosing class
at compileSourceTextModule (node:internal/modules/esm/utils:355:16)
at ModuleLoader.moduleStrategy (node:internal/modules/esm/translators:94:18)
at ModuleLoader.<anonymous> (node:internal/modules/esm/translators:689:10)
at #translate (node:internal/modules/esm/loader:441:20)
at afterLoad (node:internal/modules/esm/loader:509:29)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:514:12)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:567:36)
at afterResolve (node:internal/modules/esm/loader:614:52)
at ModuleLoader.getOrCreateModuleJob (node:internal/modules/esm/loader:620:12)
at node:internal/modules/esm/loader:639:32
Node.js v26.13.0$ npx tsc --noEmit
src/classes.ts:27:17 - error TS18013: Property '#balance' is not accessible outside class 'Account' because it has a private identifier.
27 console.log(acc.#balance);
~~~~~~~~
Found 1 error in src/classes.ts:274. Fix
We delete that line, and everything works again.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);$ npx tsc --noEmit5. implements
An interface can describe what a class must have. Square says implements Shape, so it must have an area method. If we forget it, tsc tells us. We also write public side in the constructor, a shortcut that makes a field and sets it in one go.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);
interface Shape {
area(): number;
}
class Square implements Shape {
constructor(public side: number) {}
area() {
return this.side ** 2;
}
}
console.log(new Square(3).area());$ npx tsc --noEmit6. Node error
tsc is happy, but Node is not. It stops with an error: T S parameter property is not supported. Node only removes the types and keeps everything else, and this shortcut needs real code to be generated. This is the same reason as enum in episode eighteen.
$ node src/classes.ts
node:internal/modules/run_main:111
triggerUncaughtException(
^
file:///home/mah/shop/src/classes.ts:31
class Square implements Shape {
constructor(public side: number) {}
^^^^^^^^^^^^
area() {
SyntaxError [ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX]: TypeScript parameter property is not supported in strip-only mode
at parseTypeScript (node:internal/modules/typescript:57:40)
at processTypeScriptCode (node:internal/modules/typescript:129:37)
at Object.stripTypeScriptModuleTypes (node:internal/modules/typescript:172:22)
at stripTypeScriptModuleTypes (node:internal/modules/esm/translators:35:49)
at ModuleLoader.<anonymous> (node:internal/modules/esm/translators:688:29)
at #translate (node:internal/modules/esm/loader:441:20)
at afterLoad (node:internal/modules/esm/loader:509:29)
at ModuleLoader.loadAndTranslate (node:internal/modules/esm/loader:514:12)
at #getOrCreateModuleJobAfterResolve (node:internal/modules/esm/loader:567:36)
at afterResolve (node:internal/modules/esm/loader:614:52) {
code: 'ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX'
}
Node.js v26.13.07. Fix
The fix is to write it out. A field called side, and a constructor that sets it. Now Node runs it, and the area is nine.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);
interface Shape {
area(): number;
}
class Square implements Shape {
side: number;
constructor(side: number) {
this.side = side;
}
area() {
return this.side ** 2;
}
}
console.log(new Square(3).area());$ node src/classes.ts
2
Mia 50
98. abstract
An abstract class is a blueprint that can not be used by itself. It can promise a method, here sound, that every child class must write. Dog extends Animal and answers Woof. But if we try new Animal, tsc says: cannot create an instance of an abstract class. TS2511.
src/classes.ts:
class Counter {
count = 0;
increment() {
this.count += 1;
}
}
const c = new Counter();
c.increment();
c.increment();
console.log(c.count);
class Account {
#balance = 0;
owner: string;
constructor(owner: string) {
this.owner = owner;
}
deposit(amount: number) {
this.#balance += amount;
}
get balance() {
return this.#balance;
}
}
const acc = new Account("Mia");
acc.deposit(50);
console.log(acc.owner, acc.balance);
interface Shape {
area(): number;
}
class Square implements Shape {
side: number;
constructor(side: number) {
this.side = side;
}
area() {
return this.side ** 2;
}
}
console.log(new Square(3).area());
abstract class Animal {
abstract sound(): string;
speak() {
console.log(this.sound());
}
}
class Dog extends Animal {
sound() {
return "Woof";
}
}
new Dog().speak();
const a = new Animal();$ npx tsc --noEmit
src/classes.ts:52:11 - error TS2511: Cannot create an instance of an abstract class.
52 const a = new Animal();
~~~~~~~~~~~~
Found 1 error in src/classes.ts:52Recap
Today: classes with fields and methods, the constructor, the private hash sign, implements, abstract classes, and why Node does not accept the constructor shortcut. Next episode: modules, and splitting code into files.