Sostieni AppuntiFacili con una piccola donazione su PayPal
Dona con PayPalEvery property and method you’ve seen so far in the Classes lesson belongs to an instance — each object created with new gets its own independent copy of the instance fields. The static keyword flips that: a static member belongs to the class itself, not to any particular instance. There is exactly one copy of it, shared by everyone.
Think of the difference this way: instance members answer “what does this specific object know?”, while static members answer “what does the class as a whole know?“.
class Dog {
static instanceCounter: number = 0;
private name: string;
public constructor(name: string) {
Dog.instanceCounter++;
this.name = name;
}
static decreaseCount() {
this.instanceCounter--;
}
}
Static members are accessed through the class name, never through an instance variable:
const dog1 = new Dog("Franco"); // instanceCounter = 1
console.log(Dog.instanceCounter);
const dog2 = new Dog("Bruschetta"); // instanceCounter = 2
console.log(Dog.instanceCounter);
Dog.decreaseCount();
console.log(Dog.instanceCounter); // 1
Notice that dog1.instanceCounter is not how you’d read this value — it doesn’t belong to dog1, it belongs to Dog. In fact, TypeScript will flag dog1.instanceCounter as an error: instance variables cannot see static members through this.
WARNING
A common beginner mistake is expecting each instance to carry its own copy of a static field. It doesn’t — every instance of Dog shares the exact same instanceCounter. Incrementing it from any constructor call affects the value every other instance (and the class itself) will see.
this inside a static methodInside the constructor, Dog.instanceCounter++ explicitly names the class. But inside decreaseCount(), the code uses this.instanceCounter-- instead. Why does that work?
Inside a static method, this refers to the class itself (the constructor function), not to an instance — because static methods are never called on an instance in the first place (Dog.decreaseCount(), not dog1.decreaseCount()). So this.instanceCounter inside a static method is equivalent to Dog.instanceCounter.
TIP
Using this instead of the hardcoded class name inside static methods has a practical benefit: if a subclass inherits the static method, this will correctly refer to the subclass, not the base class. This matters for patterns like static factory methods that need to work correctly across an inheritance chain.
class Counter {
static total: number = 0; // one copy, shared by the whole class
private id: number; // one copy per instance
constructor() {
Counter.total++;
this.id = Counter.total;
}
public getId(): number {
return this.id;
}
}
const a = new Counter();
const b = new Counter();
console.log(a.getId()); // 1
console.log(b.getId()); // 2
console.log(Counter.total); // 2
id is different for every Counter instance (each one remembers its own creation order), while total is one single number that every instance contributed to and that lives on the class, not on any object.
Dog example above).class User {
private constructor(public name: string) {}
static create(name: string): User {
if (!name.trim()) {
throw new Error("Name cannot be empty");
}
return new User(name);
}
}
const u = User.create("Dennis");
Map shared by every instance to look up or memoize values.static readonly MAX_SPEED = 300; on a Car class, since the value belongs conceptually to the type, not any one car.INFO
Note the private constructor in the factory example: combining a private constructor with a public static method is a common pattern to force all object creation to go through validated, controlled entry points instead of a bare new User(...).
What does the `static` keyword mean when applied to a class member?
How should you access a static property named `total` on a class `Counter`?
Inside a static method, what does `this` refer to?
If `Dog.instanceCounter` is incremented in the constructor every time `new Dog(...)` runs, what happens to previously created instances?
Which of these is a typical real-world use case for a static method?
Why might combining a `private constructor` with a `static create()` method be useful?
Scenario: You’re building a simple ticketing system where every issued ticket needs a unique, sequential ID.
Task:
Ticket with a static nextId: number = 1 and a private readonly id: number.this.id = Ticket.nextId and then increment Ticket.nextId.getId(): number and a static method static getIssuedCount(): number that returns how many tickets have been issued so far.Ticket instances and print each one’s ID plus the total issued count.Learning objective: understand how static fields maintain shared state across all instances, distinct from per-instance fields.
Scenario: You want a small in-memory cache shared by every instance of a Config class, so expensive lookups aren’t repeated.
Task:
Config with a private static cache: Map<string, string> = new Map().static getOrCompute(key: string, compute: () => string): string that returns the cached value if present, otherwise computes it with compute(), stores it in the cache, and returns it.getOrCompute twice with the same key but a compute callback that logs "computing..." — verify the log only appears once.cache needed to be static rather than an instance field for this to work.Learning objective: apply static members to implement a shared cache pattern and clarify the difference between per-instance and per-class state.
Prenota una lezione