What are intrinsic types and how are they defined in TypeScript? Why is the intrinsic keyword needed in its type system?
Even though the notion of intrinsic types might baffle the reader, I will not define them right away, as I want to introduce the concept using a practical example. I would love to start the article with the following question, something I have asked myself in various forms over the years:
In an ideal, statically-typed language, how could one define the string capitalisation type, using the properties of its type system?
I could substitute string capitalisation with string permutation and the issue still remains valid, as long as it touches not the abstraction of types, but their intrinsic properties.
The way I wrote the aforementioned assignment grants a lot of freedom in regards to choosing the utilised type system. However, one must recognise implicit requirements for certain features, like generics, string literals or inheritance. Since ordered lists of characters make strings, the question “which encoding applies to characters?” requires an instant answer.
I would name the type CapitalizedString and define it as a parametrised type (or a generic type, depends on the domain language of the chosen type system) with the single parameter T constrained to a string literal type. All characters in strings should adhere to the UTF-8 encoding. One could write it down easily using pseudocode in the following fashion:
type CapitalizedString<T extends string literal> = ...
By definition, if the string literal in question has no characters, the operation has obviously no effect on it. Otherwise, capitalisation alters only the first character of the string in question, leaving the rest unchanged. To uppercase a character, the type system needs to support it ad hoc, as defining it explicitly in the type system sounds impractical for UTF-8 characters due to complexity of such an algorithm (I find it inadvisable even for ASCII characters).
Therefore, the compiler itself must provide implementation of uppercasing any UTF-8 character, making the uppercase operation an ad hoc, or rather an intrinsic property of the type system. There exist multiple ways of declaring such a property in type definitions, for example:
intrinsic type Uppercase<T extends character>; type Uppercase<T extends character> = intrinsic;
An avid reader might note that the aforewritten definitions provide no return type explicitly — since the compiler performs the operation, nobody knows the return type beforehand. The type system might define uppercasing as an unary operator, accepting a single character, as shown in the following snippet:
type UppercaseA = uppercase 'a';
In the end, the CapitalisedString type boils down to the following definition:
type CapitalisedString<T extends string literal> = T === '' ? '' : Uppercase<T> + T[1...];
In order for the definition to work, the type system in question requires:
A type system is a set of rules for performing various consistency and correctness checks in a program. There are various definitions and classifications for type systems
In this lesson, we are going to learn about the fundamentals of TypeScript and how TypeScript manages types. This lesson includes topics such as type assertion, type interference, type unions, type guards, structural typing, and other important concepts that you should absolutely know about.
Type systems are typically categorized as either structural or nominal. Languages like Java and Scala have primarily nominal type systems, whereas a language like Typescript has a structural type system. Let’s take a brief look at both systems.