When working with TypeScript, one of the key concepts that improves code safety and readability is type relationships. Two of the most important relationships are Super Type and SubType. Let’s break them down step by step.
What is a Super Type?
A Super Type is a more general type.
It contains a base set of properties and/or methods that can be shared across multiple related types.
- Think of it as a blueprint with fewer details.
- Other types can build on it, expand it, and add new features.
For example:
type Animal = {
name: string;
eat(): void;
};
Here, Animal is a super type. It says that every animal must have a name and a method eat.
What is a SubType?
A SubType is a more specific version of a super type.
It includes everything from the super type plus it can add its own unique properties and methods.
- A subtype must at least satisfy all requirements of the super type.
- It can extend the functionality by introducing additional details.
Example:
type Dog = {
name: string;
eat(): void;
bark(): void; // extra method only for Dog
};
Here, Dog is a subtype of Animal.
It still has name and eat() from Animal, but it also introduces a new method bark().
Relationship Between Super Type and SubType
- Every subtype is compatible with its super type.
- A
Dogis anAnimal, so aDogcan always be used where anAnimalis expected.
- A
- But not every super type can be used as a subtype.
- An
Animalis not necessarily a Dog, because not all animals canbark().
- An
This is why assignment works one way but not always the other:
let animal: Animal;
let dog: Dog = {
name: "Rex",
eat() { console.log("eating"); },
bark() { console.log("barking"); }
};
// ✅ Subtype assigned to Super type
animal = dog;
// ❌ Error: Super type cannot always be assigned to Subtype
dog = animal;
// Property 'bark' is missing in type 'Animal'
Key Rule of Subtyping
- Subtype → Supertype assignment works: Safe, because the subtype has everything the supertype requires.
- Supertype → Subtype assignment does not always work: Unsafe, because the supertype might lack the extra properties/methods the subtype expects.
Why This Matters in TypeScript?
Understanding super types and subtypes helps developers:
- Write reusable code: Define general contracts with supertypes and extend them for specific needs with subtypes.
- Avoid runtime errors: TypeScript catches mistakes at compile time if you misuse types.
- Model real-world hierarchies: For example, in OOP,
Employeecould be a supertype, whileManagerandDeveloperare subtypes.
Real Example: Interfaces and Inheritance
TypeScript makes it easy to express these relationships with interface and extends:
interface Vehicle {
move(): void;
}
interface Car extends Vehicle {
fuel: string;
}
const myCar: Car = {
move() { console.log("driving"); },
fuel: "petrol"
};
let vehicle: Vehicle = myCar; // ✅ Works
// let car: Car = vehicle; // ❌ Error: 'fuel' is missing
Conclusion
- A Super Type defines a general contract (fewer properties/methods).
- A SubType builds upon it, adding more properties/methods.
- Subtypes can always be assigned to supertypes, but the reverse requires extra checks or type adjustments.
This relationship is central to how TypeScript enforces type safety while still allowing flexibility in designing your code.