HomepageExploring TypeScript (TS 5.8 Edition)
You can support this book: buy it or donate
(Ad, please don’t block.)

13 What is a type in TypeScript? Two perspectives

What are types in TypeScript? This chapter describes two perspectives that help with understanding them. Both are useful; they complement each other.

13.1 Two questions for each perspective

The following two questions are important for understanding how types work and need to be answered from each of the two perspectives.

  1. What does it mean for arg to have the type MyType?

    function myFunc(arg: MyType): void {}
    
  2. How is UnionType derived from Type1 and Type2?

    type UnionType = Type1 | Type2;
    

13.2 Dynamic perspective: a type is a set of values

From this perspective, we are interested in values and a type is a set of values:

  1. We can pass a given value to myFunc() if it is included in MyType.
  2. UnionType (a set) is defined as the set-theoretic union of Type1 and Type2.

13.3 Static perspective: relationships between types

From this perspective:

The most important type relationship is assignment compatibility: Can a location whose type is Src be assigned to a location whose type is Trg? The answer is yes if:

Let’s consider the questions:

  1. Parameter arg having type MyType means that we can only pass a value to myFunc() whose type is assignable to MyType.
  2. UnionType is defined by the relationships it has with other types. Above, we have seen two rules for union types.

13.4 Nominal type systems vs. structural type systems

One of the responsibilities of a static type system is to determine if two static types are compatible – e.g.:

The type system needs to check if Src is assignable to Trg. Two approaches for this check are (roughly):

The following code produces a type error in the last line with a nominal type system, but is legal with TypeScript’s structural type system because class A and class B have the same structure:

class A {
  typeName = 'A';
}
class B {
  typeName = 'B';
}
const someVariable: A = new B();

TypeScript’s interfaces also work structurally – they don’t have to be implemented in order to match:

interface HasTypeName {
  typeName: string;
}
const hasTypeName: HasTypeName = new A(); // OK

13.5 Further reading