Structural Types in TypeScript

Nominal v. Structural Type Checking

One of the most important concepts to grasp about TypeScript is that in TypeScript type checking is not nominal but structural.

In a nominal type system type compatibility of an object is being checked not based on its structure (its shape) but the basis of its class or prototype.

In a nominal type system an object value cannot be assigned to a variable, parameter or property when that object value is of a different class to the class declared for that variable, parameter or property irrespective of whether the object is compatible structurally.

class Student {
  first_name: string
  last_name: string
}

class Teacher {
  first_name: string
  last_name: string
}

student_a: Student = new Teacher() // An error is thrown!

C++, C#, Java, and Swift primarily use the nominal typing system.

On the other hand, in a structural type system an object value cannot be assigned to a variable, parameter, or property only when the object value differs structurally from the type declaration of that variable, parameter, or property, and classes are not taken into account.

TypeScript features structural type system and therefore the below is fully acceptable.

class Student {
  firstName: string
  lastName: string
}

class Teacher {
  firstName: string
  lastName: string
}

let studentA: Student = new Teacher() // OK!

In a structural type system, only an object's structure and not its class is taken into account when checking type compatibility.

TypeScript is an example of a structural type system. Other examples of structurally typed languages are Haskell and Elm.

Literal Structural Types

A literal structural type is a structural type without a name assigned to it.

A literal structural type cannot be declared or exist by itself. It can only be used as:

  • a variable type annotation,

  • an object property type annotation,

  • a function parameter type annotation,

  • a function return type annotation, and

  • a named structural type assignment.

// a variable type annotation
let car: { brand: string, year: number }

// an object property type annotation
let customer: { address: { street: string, city: string }}

// a function parameter type annotation
function logPerson(person: { firstName: string, lastName: string }) {
  console.log(person)
}

// a function return type annotation
function getAddress(person: { address: { street: string, city: string }}): { street: string, city: string } {
  return person.address
}

Named Structural Types

In TypeScript, a named structural type is declared using the keyword type appended with a name and with a literal structural type assigned to it.

type Student = {
  firstName: string,
  lastName: string
}

A property type of a structural type can be a named type itself.

type Address = {
  street: string,
  city: string
}

type Student = {
  firstName: string,
  lastName: string,
  address: Address,
  major: {
    name: string,
    department: string
  }
}

In the above example the address property type is specified using the named type Address and the major property type is specified using the literal type { name: string, department: string }.

We use cookies and similar technologies to enhance the quality of services, maintain statistics and adjust marketing content. You will find more information in the Cookies Policy.

By clicking OK you grant consent to processing of your personal data by us and our Trusted Partners with the purpose of maintain statistics and adjustment of the marketing content pursuant to the Privacy Policy. If you wish to not grant that consent and/or limit its extent click Settings.