A very brief introduction to nominal & structural type systems

Last week I was listening to .NET Rocks #1460. Carl Franklin and Richard Campbell were talking with Anders Hejlsberg about TypeScript. At one point Anders Hejlsberg mentioned one thing I was totally ignorant about - structural type system of TypeScript. I did a little bit of research and I’ve learned that type systems can be divided to two major categories - nominal & structural.

Nominal Type System

Let’s start with what I’ve already known and most programmers are used to - the nominal type system. It’s because we are used to it from C++, C#, F#, Swift or Rust.

In this context, the word nominal means based on it’s name. If we consider parent class and interfaces class implements as part of the name, things start to make sense.

Let’s consider this example in C#.

interface HasName
{
    string Name { get; }
}

class Person : HasName
{
    public string Name { get; }
    // ...
}

class Employee : Person
{
    // ...
}

class Car 
{
    public string Name { get; }
}

void Main()
{
    HasName a;

    // This works becase Person implements HasName
    a = new Person(); 
    
    // This works because Employee inherits from Person
    // which implements HasName
    a = new Employee(); 

    // This doesn't work. Considering only "name" of the class,
    // Car doesn't have anything in common with HasName.
    a = new Car();  
}

Structural Type System

In structural type systems compatibility of two types is determined by the structure of that types. Languages that are using structural typing are to some extend OCaml, Haskell, Go and TypeScript.

Let’s rewrite previous example in TypeScript.

interface HasName {
    name: string;
}

class Person implements HasName {
    name: string;
    // ...
}

class Employee extends Person {
    // ...
}

class Car {
    name: string;
}

let a: HasName;

// This works
a = new Person(); 

// This works
a = new Employee(); 

// This works as well because of structural typing
a = new Car();  

Conclusion

In this post we show on examples of C# and TypeScript how nominal and structural type systems differ. Of course this topic carries many intriguing details. If you like to hear about them, please let me know.

References