{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreie6wqobgcwfbowc7dx4icio7nb2utn3mwnu7mcgu4vknmnoe53kvu",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mommxoat5qf2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreierp5gsawgwi42oqyuy23edrszfbqy3jxzx7xxqnhed7zlccvppom"
},
"mimeType": "image/webp",
"size": 62324
},
"path": "/jsha/typescript-object-oriented-programming-oop-3o5g",
"publishedAt": "2026-06-19T05:22:59.000Z",
"site": "https://dev.to",
"tags": [
"beginners",
"javascript",
"tutorial",
"typescript"
],
"textContent": "When we hear about OOP, what is the first thing that comes to mind? Classes!\n\n## Basic structure\n\nClasses in TypeScript look pretty the same as in JavaScript only with specifying types.\n\n\n\n class Person {\n name: string;\n constructor(name: string) {\n this.name = name;\n }\n greet() {\n console.log(`Welcome, ${this.name}!`);\n }\n }\n\n const p1 = new Person(\"Mary\");\n\n p1.greet(); // Welcome, Mary!\n\n\n## Access modifiers\n\nWe can restrict or open access to specific properties or methods by using keywords:\n\n### Private modifier\n\nThe **private** modifier makes a property available only within the class.\n\n\n\n class Person {\n private name: string;\n constructor(name: string) {\n this.name = name;\n }\n greet() {\n console.log(`Welcome, ${this.name}!`);\n }\n }\n\n const p1 = new Person(\"Mary\");\n\n console.log(p1.name); // Property 'name' is private and only accessible within class 'Person'\n\n\nBut how would we read it ouside the class? Here comes _getter_ :\n\n\n\n class Person {\n private name: string;\n constructor(name: string) {\n this.name = name;\n }\n greet() {\n console.log(`Welcome, ${this.name}!`);\n }\n getName() {\n return this.name;\n }\n }\n\n const p1 = new Person(\"Mary\");\n\n console.log(p1.getName()); // Mary\n\n\nWe can also use _setter_ to change the private property (we can also set some conditions):\n\n\n\n class Person {\n private name: string;\n constructor(name: string) {\n this.name = name;\n }\n greet() {\n console.log(`Welcome, ${this.name}!`);\n }\n setName(name: string) {\n if (name.length < 5) return;\n this.name = name;\n }\n }\n\n\n### Public modifier\n\nActually, this value is there by default.\n\n\n\n class Person {\n public name: string;\n constructor(name: string) {\n this.name = name;\n }\n greet() {\n console.log(`Welcome, ${this.name}!`);\n }\n }\n\n const p1 = new Person(\"Mary\");\n\n console.log(p1.name); // Mary\n\n\n### Protected modifier\n\nThe **protected** modifier makes a property available only within the class and its subclasses:\n\n\n\n class Person {\n protected name: string;\n constructor(name: string) {\n this.name = name;\n }\n }\n\n class User extends Person {\n greet() {\n console.log(`Hello there, ${this.name}`);\n }\n }\n\n const p1 = new User(\"Mary\");\n\n console.log(p1.greet());\n\n\n### Readonly modifier\n\nThe **readonly** modifier prevents the property from being modified outside of the constructor:\n\n\n\n class Person {\n readonly name: string = \"No name\";\n constructor(otherName: string) {\n this.name = otherName;\n }\n changeName(otherName: string) {\n this.name = otherName; // Cannot assign to 'name' because it is a read-only property\n }\n }\n\n const p1 = new Person(\"Mary\");\n p1.name = \"Ann\"; // Cannot assign to 'name' because it is a read-only property\n\n\n> We can also use it for interfaces:\n>\n\n\n interface User {\n readonly password: string;\n name: string;\n }\n\n let user: User = {\n password: 'password',\n name: 'John Smith'\n }\n\n user.name = 'Mary Smith';\n\n user.password = 'newPassword'; //Cannot assign to 'password' because it is a read-only property.\n\n\n## Abstract class\n\nThis is a restricted class (we can't create instances from it), from which we can create subclasses. It's usually used to define mandatory methods.\n\n\n\n abstract class Dog {\n abstract bark(duration: number): void;\n\n walk(duration: number) {\n console.log(\"Walking\");\n this.bark(duration);\n }\n }\n\n class Husky extends Dog {\n bark(duration: number) {\n console.log(\"Wooooooo\");\n }\n }\n\n class Chihuahua extends Dog {\n bark(duration: number) {\n console.log(\"wof wof wof\");\n }\n }\n\n let d1 = new Husky();\n\n d1.walk(2);\n\n\n> Here, subclasses must implement their own `bark` method, since it's defined with keywork `abstract`. They inherited the method `walk`.\n\n## Classes and interfaces\n\nClasses can implement an interface, that allows to treat instances from different classes (that implement the same interface) as the same object hiding complexity, that we don't care about it at this moment:\n\n\n\n interface MakeSound {\n makeSound(): void;\n }\n\n class Python implements MakeSound {\n length: number;\n\n constructor(length: number) {\n this.length = length;\n }\n\n makeSound() {\n console.log('Ssssss!');\n }\n }\n\n class Puma implements MakeSound {\n makeSound() {\n console.log('Roar!');\n }\n }\n\n const python = new Python(10);\n const puma = new Puma();\n\n function animalSpeak(animal: MakeSound) {\n animal.makeSound();\n }\n\n animalSpeak(python);\n animalSpeak(puma);\n\n\n> function `animalSpeak` is interested only in the ability of object to _makeSound_ , it doesn't care if the object is python or puma.\n\n## Static method and field\n\nLike in JavaScript, we can define `static` methods and fields for a class. They cannot be accessed on instances, but on the class itself. We can use it to create some shared values or maybe count instances that exist:\n\n\n\n class Person {\n static instanceCount: number = 0;\n name: string;\n\n constructor(name: string) {\n Person.instanceCount++;\n this.name = name;\n }\n }\n\n const p1 = new Person('Mary');\n const p2 = new Person('Tom');\n console.log(Person.instanceCount); // 2\n\n\nWe also can define `static` method:\n\n\n\n class Person {\n static instanceCount: number = 0;\n name: string;\n\n constructor(name: string) {\n Person.instanceCount++;\n this.name = name;\n }\n\n static clearCount() {\n this.instanceCount = 0;\n }\n }\n\n const p1 = new Person('Mary');\n const p2 = new Person('Tom');\n Person.clearCount();\n console.log(Person.instanceCount); // 0\n\n\n> Static methods can only access variables that associate with the class.",
"title": "TypeScript. Object-oriented programming (OOP)"
}