3.7 Named Types

Classes, interfaces, enums, and type aliases are named types that are introduced through class declarations (section 8.1), interface declarations (section 7.1), enum declarations (9.1), and type alias declarations (section 3.10). Classes, interfaces, and type aliases may have type parameters and are then called generic types. Conversely, named types without type parameters are called non-generic types.

Interface declarations only introduce named types, whereas class declarations introduce named types and constructor functions that create instances of implementations of those named types. The named types introduced by class and interface declarations have only minor differences (classes can’t declare optional members and interfaces can’t declare private or protected members) and are in most contexts interchangeable. In particular, class declarations with only public members introduce named types that function exactly like those created by interface declarations.

Named types are referenced through type references (section 3.8.2) that specify a type name and, if applicable, the type arguments to be substituted for the type parameters of the named type.

Named types are technically not types—only references to named types are. This distinction is particularly evident with generic types: Generic types are “templates” from which multiple actual types can be created by writing type references that supply type arguments to substitute in place of the generic type’s type parameters. This substitution process is known as instantiating a generic type. Only once a generic type is instantiated does it denote an actual type.

TypeScript has a structural type system, and therefore an instantiation of a generic type is indistinguishable from an equivalent manually written expansion. For example, given the declaration

  1. interface Pair<T1, T2> { first: T1; second: T2; }

the type reference

  1. Pair<string, Entity>

is indistinguishable from the type

  1. { first: string; second: Entity; }