
Structural type system
In the type system of a programming language, a type is an object with a name and a structure. Some types have very simple data structures (such as primitives) while others use complex structures (such as classes).
The type system can use two different strategies to validate that a given value matches the desired type:
- Nominal type system: In this type system, values are matched against a type by its name
- Structural type system: In this type system, values are matched against a type by its structure
The TypeScript type system is a structural type system because the values are matched against a type by its structure, as the following code snippet demonstrates:
interface Person {
name: string; surname: string; } function getFullName(person: Person) { return `${person.name} ${person.surname}`; } class Employer { constructor( public name: string, public surname: string ) {} } getFullName(new Employer("remo", "jansen")); // OK const p1 = { name: "remo", surname: "jansen" }; getFullName(p1); // OK const p2 = { name: "remo", familyName: "jansen" }; getFullName(p2); // Error
In the preceding code snippet, we can observe how the first two calls to the getFullName function are successful because the structure (properties and types) of both the Employer instance and the object literal match the structure of the Person interface.
The following code snippet showcases how TypeScript would work if it used a nominal type system:
interface Person {
name: string;
surname: string;
}
function getFullName(person: Person) {
return `${person.name} ${person.surname}`;
}
class Employer implements Person { // Named!
constructor(
public name: string,
public surname: string
) {}
}
getFullName(new Employer("remo", "jansen")); // OK
const p1: Person = { name: "remo", surname: "jansen" }; // Named!
getFullName(p1); // OK
const p2: Person = { name: "remo", familyName: "jansen" }; // Error
getFullName(p2); // OK
The first call to getFullName works because the Employer class implements the Person interface, and the name of the type of the interface can then be matched against the name of the type of the function argument.