Learn how to build abstract base classes, define abstract method contracts, and implement template method patterns.
Discover how TypeScript infers types automatically and how let versus const declarations shape wide types versus narrow literal types.
An Abstract Class is a base class that CANNOT be instantiated directly using new. It exists solely to be extended by child subclasses.
Unlike interfaces (which are completely erased at compile time), abstract classes exist at runtime while allowing you to share concrete implementation methods alongside abstract method contracts.
Mark the class and missing method signatures with the abstract keyword:
abstract class BaseRepository<T> {
// Shared concrete helper method
public logOperation(op: string): void {
console.log(`[DB OP]: ${op} at ${new Date().toISOString()}`);
}
// Abstract method contract (Subclasses MUST implement this!)
abstract findById(id: string): Promise<T | null>;
abstract save(entity: T): Promise<void>;
}
interface UserEntity { id: string; name: string }
class UserRepository extends BaseRepository<UserEntity> {
async findById(id: string): Promise<UserEntity | null> {
this.logOperation(`findById: ${id}`);
return { id, name: "Alex" };
}
async save(entity: UserEntity): Promise<void> {
this.logOperation(`save: ${entity.id}`);
}
}
| Feature | Abstract Class | Interface |
|---|---|---|
| Runtime JS Code | Generates real JS class code | Erased completely at compile time |
| Concrete Methods | Can contain real code methods | Signatures only (No code) |
| Direct Instantiation | Impossible (new Base() errors) | Impossible |
new BaseClass(): Trying to instantiate an abstract class directly throws compile error: Cannot create an instance of an abstract class.Use abstract classes for template design patterns. Next, let's explore Ambient Declarations and Declaration Files (.d.ts)!