Nominal typing and structural typing are two different ways programming languages handle type comparisons and assignments. They differ in the way they handle type compatibility between objects and classes/interfaces. Here are their definitions and how TypeScript relates to these concepts:
1. Nominal Typing:
In languages that use nominal typing, two types are considered compatible if they have the same declared type. That is, two objects are considered to have the same type if they were explicitly derived from the same class, interface, or provided type label. Nominal typing is also called name-based typing because it compares types based on their names.
Here’s an example in a hypothetical smooth pseudo-code that uses nominal typing:
class Person {
name: string;
}
class Employee {
name: string;
}
const person: Person = new Person();
const employee: Employee = new Employee();
// This would result in a type error, even though both objects share
// the same properties and structure.
person = employee;
In this example, even though the ‘Person‘ and ‘Employee‘ classes have the same structure, they are considered to be different types because they have been explicitly labeled as such.
2. Structural Typing:
Languages that use structural typing consider two types compatible if they have the same structure—i.e., if an object has all the properties that another object requires, the two objects are considered to have the same type. Structural typing is also called "duck typing" or "shape-driven typing."
TypeScript is a structurally-typed language, meaning that it uses structural typing to determine type compatibility.
Here’s an example of the same ‘Person‘ and ‘Employee‘ classes in TypeScript:
interface Person {
name: string;
}
interface Employee {
name: string;
}
const person: Person = { name: "Alice" };
const employee: Employee = { name: "Bob" };
// This is okay in TypeScript because both templates share
// the same structure.
person = employee;
In this TypeScript example, the ‘person‘ and ‘employee‘ objects can be assigned to each other because their structures match, even though they are annotated with different interface names.
In summary, TypeScript is a structurally-typed language, which means it checks the compatibility between types based on their structures, rather than their names. This behavior allows for more flexibility in code organization and enables better code reuse without having to explicitly extend or implement common interfaces.