TypeScript
Completed
-
Section 1: Getting Started
-
Section 2: Basic Types
-
Section 3: Functions and Objects
-
Section 4: Advanced Types
-
Section 5: Object-Oriented TypeScript
-
Section 6: Working with Modules
-
Section 7: Tooling and Practice
-
Section 8: Type-Level Programming
-
Section 9: TypeScript with Backends
-
Section 10: Testing Typed Code
-
Section 11: Data Validation with Types
-
Section 12: Practical Projects
-
Section 13: Compiler Internals
-
Section 14: Configuration Deep Dive
-
Section 15: Enums, Symbols, and Special Types
-
Section 16: Working with Async Code
-
Section 17: TypeScript and the DOM
-
Section 18: Advanced Generics Practice
-
Section 19: Working with Third-Party Types
-
Section 20: Monorepo and Large-Scale Practices
-
Section 21: Common Pitfalls and Best Practices
-
Section 22: Interview Practice
-
Section 23: Handbook: Narrowing In Depth
-
Section 24: Handbook: Object Types In Depth
-
Section 25: Handbook: Classes In Depth
-
Section 26: Handbook: Modules In Depth
-
Section 27: Handbook: Declaration Files In Depth
-
Section 28: JSX and Namespaces
-
Section 29: Compiler Configuration Reference
-
Section 30: More Practice Exercises
-
Section 31: Handbook: Everyday Types Deep Dive
-
Section 32: Utility Types Full Reference
-
Section 33: Decorators Reference
-
Section 34: Mixins and Advanced OOP Patterns
-
Section 35: Iterators and Generators Typing
-
Section 36: More Type-Level Programming Practice
-
Section 37: TypeScript Ecosystem Tools
-
Section 38: TypeScript with Testing Frameworks
-
Section 39: TypeScript for Library Authors
-
Section 40: More Interview Practice
-
Section 41: Handbook: Functions In Depth
-
Section 42: Handbook: Type Manipulation Deep Dive
-
Section 43: More Real-World Patterns
-
Section 44: TypeScript Release Notes Highlights
-
Section 45: Final Practice and Review
45: Static Members in Classes
Up until now, everything we've done with classes has been about the instance. You create a blueprint, you instantiate it with new, and that object holds its own unique state. But every now and then, you'll run into a situation where you need a piece of data that belongs to the class itself, regardless of how many objects you've created from it.
That's where static members come in. Think of them as "class-level" variables or functions rather than "object-level" ones.
Tracking something across all players
Let's say we're building a simple multiplayer game. We want each Player object to have its own name and score, but we also want to keep a running tally of exactly how many players have joined the game session globally. If I put playerCount as a regular property, every single player would start with their own count of 1, which is useless.
Instead, I'll make it static. Here is how I'd start this:
class Player {
static playerCount: number = 0;
constructor(public name: string) {
// Every time a new Player is created, increment the global count
Player.playerCount++;
console.log(`${this.name} joined. Total players: ${Player.playerCount}`);
}
}
const p1 = new Player("Alice"); // Total players: 1
const p2 = new Player("Bob"); // Total players: 2
Notice how I used Player.playerCount inside the constructor. I'm accessing the property on the class definition itself, not on this.
Hitting a wall with 'this'
Now, here is a mistake I actually made early on when I first started with static members. I tried to create a method to describe the player's status, and I tried to pull in that global count using this. It looked like this:
class Player {
static playerCount: number = 0;
constructor(public name: string) {
Player.playerCount++;
}
getPlayerStatus() {
// Oops! This is where I messed up.
return `${this.name} is one of ${this.playerCount} players.`;
}
}
TypeScript will immediately yell at me here. It'll tell me that playerCount doesn't exist on type Player. It's a confusing error at first glance because you can see the property right there in the class. But remember: this refers to the instance (Alice or Bob), and static members don't live on the instance; they live on the constructor function.
To fix this, I just have to be explicit about where that data lives:
getPlayerStatus() {
// Access via the Class name, not 'this'
return `${this.name} is one of ${Player.playerCount} players.`;
}
Adding a helper that doesn't need an instance
Static properties are great, but static methods are where things get really useful. Sometimes you want a utility function that is logically related to the class, but doesn't actually need a specific object to do its job. In our game, we might want a way to reset the game session without needing to have a Player object handy.
I'll add a static method to handle the reset logic:
class Player {
static playerCount: number = 0;
constructor(public name: string) {
Player.playerCount++;
}
// This method belongs to the class, not the object
static resetSession() {
this.playerCount = 0;
console.log("Session reset. All players cleared.");
}
}
// I don't need to call 'new Player()' to use this
Player.resetSession();
A quick tip: inside a static method, this actually refers to the class itself, not an instance. That's why I could use this.playerCount inside resetSession(). It's a bit of a mind-bender, but once you realize that the class itself is technically an object in JavaScript/TypeScript, it starts to make sense.
📋 Practical Task
Implementing a Global User Session Counter
You are building a backend system to track active database connections. Your goal is to ensure that the system knows exactly how many connections are open across the entire application, regardless of which specific connection object is being used.
Requirements:
- Create a class named
DatabaseConnection. - Add a
staticproperty calledactiveConnections(number) initialized to 0. - The
constructorshould accept aconnectionString(string) and increment theactiveConnectionscount. - Create a
staticmethod calledgetConnectionCount()that returns a string:"There are currently X active connections." - Create an instance method called
closeConnection()that decrements theactiveConnectionscount.
Test your code:
Instantiate three connections, call getConnectionCount() to verify the number is 3, close one connection, and verify the count is now 2.
There are no comments for now.