While working on a project and creating classes, I faced a dilemma about which access modifiers to use: public
? private
? static
? public static
? or private static
? When should private static
be used?
In this article, I'll discuss each type of access modifier and its usage.
Access modifiers are an essential part of Object-Oriented Programming, but I'll focus on their usage in TypeScript.
public
This is the default, or we can explicitly write public
.
All public members are accessible from anywhere without any restrictions.
class User {
username?: string;
public email?: string;
}
let user = new User();
user.username = "John";
user.email = "xyz@example.com";
private
Class members are only visible within the class and are not accessible outside of it.
class User {
public username?: string;
private email?: string;
}
let user = new User();
user.username = "John";
user.email = "xyz@example.com"; // Error: Property 'email' is private and only accessible within class 'User'.
static
Static properties cannot be directly accessed on instances of the class. Instead, they're accessed on the class itself.
MDN
class User {
static username = "John";
static email = "xyz@example.com";
static staticMethod(){
return "staticMethod is called";
}
}
console.log(User.username); // "John"
console.log(User.email); // "xyz@example.com"
console.log(User.staticMethod()) // "staticMethod is called"
let user = new User()
console.log(user.username) // Error
Error: user.username
JavaScript: Returns undefined
because the property does not exist on the instance
TypeScript: Gives a compile-time error
When is static
used?
According to MDN,
Static methods are often utility functions, such as functions to create or clone objects, whereas static properties are useful for caches, fixed-configuration, or any other data you don't need to be replicated across instances.
Here are the use cases:
Constant Values
Provide a single source of truth for constants
class MathConstant {
static pie = 3.14;
}
console.log(MathConstant.pie);
Utility Functions
Perform common operations or calculations that are broadly useful and don't depend on instant-specific data
class MathUtils {
static add(a: number, b: number){
return a + b;
}
}
console.log(MathUtils.add(5, 3));
Cache for Data
Share a common cache across all instances to avoid redundant data storage
class CacheData {
static cache: {[key: string]: string} = {};
static set(key: string, value: string){
this.cache[key] = value;
}
static get(key: string): string | undefined {
return this.cache[key];
}
}
Configuration Settings
Maintain a single source of configuration that can be accessed and modified globally
class Config {
static settings: { [key: string]: string } = {
theme: 'dark',
lang: 'en'
}
static updateSettings(key: string, value: string){
this.settings[key] = value;
}
}
Unique Identifier Generator
Ensure unique identifiers across the application
class UniqueID {
static ID = 0;
static generateID(){
return ++this.ID;
}
}
private static
While public static members are accessible both within the class and outside the class using the class name, private static members are only accessible within the class where they are declared. Private static members are not accessible outside the class or from its subclasses.
The main purpose of private static is encapsulation and data hiding.
class Count {
private static count: number = 0;
static increment(){
// Either approach works
// this.count++;
Count.count++;
}
static getCount(){
// Either approach works
// return this.count;
return Count.count;
}
}
Count.increment();
Count.increment();
Count.increment();
console.log(Count.getCount()); // 3
In this small example, public static might produce the same result, but it violates the encapsulation.
Access modifiers are fundamental concepts that I learned when I started programming. However, as a project grows larger and its structure needs to be well-considered, I need to think through the details more thoroughly.
Top comments (0)