Understanding the basic Built-in Data Types provided by TypeScript

In this lesson, we are going to learn about the building blocks of TypeScript's type system. Here, we are mainly going to focus on the primitive data types provided by the TypeScript.

In TypeScript, the type of a variable is denoted using :<type> annotation where <type> is any valid data type. Unlike programming languages like C and C++ in which the type of a variable is declared before the variable name like int a or void someFunc(), in TypeScript, the type annotation comes after the variable name, also known as the postfix type notation.

let fruit: string = "Mango";

In the above program, :string signifies that the variable fruit contains string data. If you are claustrophobic, you can add space between the colon and the data type, like let fruit: string which is generally preferred.

In the above example, we have defined a few variables. Some of these variables have an initial value such as age, car and canDrive while others such as person do not.

TypeScript allows undefined or null as the value for a variable even though its type might say something else. For example, person variable can hold only string data but its value is undefined at the beginning. Similarly, age can hold only number data but it was initialized with the null value.

You can also override a variable with undefined or null value after it declared at any given moment. TypeScript considers undefined and null as the Null values or empty values. Though null and undefined are types in itself as we will learn in a bit, TypeScript doesn’t allow a variable to be Null (empty) by default.

To disable this behavior, we need to set strictNullChecks compiler-option to true. This will instruct the TypeScript compiler to disallow variables to hold undefined or null value. In this mode, the variable must hold a value of its type before consumption.

As you can see from the above example, once we set strictNullChecks to true in the tsconfig.json, TypeScript doesn’t allow assignment of the null or the undefined with a variable that can’t contain null or undefined value.

Though TypeScript allows you to declare a variable without an initial value, in which case its value will be undefined implicitly, it expects from you that the variable will be assigned with a valid value in the future. If you try to use a variable without a value such as person in the above case, the TypeScript compiler will throw an error saying Varibale <x> is used before being assigned as you can see from the above results.

💡 You can learn more about the tsconfig.json and compiler-options from the Compilation lesson.

TypeScript allows us to add type annotations to any entities we like whether it’s a variable or a constant or a function or a class or a simple object. We can also configure types of the internal structure of these entities such as parameters and return value of a function or properties and methods of a class or properties of a plain object.

Built-in Data Types

In upcoming tutorials, we will look into some complex data types such as interfaces, enums, classes, and more but for now, let’s focus on some of the basic types provided by Go out of the box.

Before we proceed, I want to point out a few things first. A primitive type is an individual type that can not be broken down further. An abstract type is a type that is composed of primitive types. For example, Array<string> is an abstract type since it is an array composed of string primitive types.

💡 Do not compare TypeScript primitive types with JavaScript runtime-types since these are two different things. For example, object type in TypeScript is primitive while object type in JavaScript is abstract.

boolean

The boolean type represents true and false values. It is one of the primitive data types in TypeScript. Its corresponding JavaScript primitive type is boolean and its JavaScript constructor is Boolean.

A value of type boolean can be presented using a literal notation or using the Boolean constructor.

number

The number type represents all real numbers (integers and floating-point numbers). It is one of the primitive data types in TypeScript. Its corresponding JavaScript primitive type is number and its JavaScript constructor is Number.

A value of type number can be presented using a literal notation or using the Number constructor.

💡 You can also use the binary 0b, octal 0o or the hexadecimal 0x prefix to represent an integer value, for example let count: number = 0x65 for the value of decimal 101. These values are converted to the decimal numbers on the fly.

string

The string type represents textual data. It is one of the primitive data types in TypeScript. Its corresponding JavaScript primitive type is string and its JavaScript constructor is String.

A value of type string can be presented using a literal notation (_using single quotes, double quotes or _template string notation) or using the String constructor.

symbol

EcmaScript 2015 added the new JavaScript primitive type symbol in the JavaScript specifications just like string, number, boolean etc. However, unlike other primitive data types, a symbol does not have a literal form.

To create a symbol, we need to call the Symbol() function that always returns a new symbol. TypeScript added the symbol primitive type to represent JavaScript symbol values.

You can pass an optional argument as a label for the symbol in the Symbol() function call, however, this is only used for debugging purposes. Every Symbol() call, with or without label always produces a unique symbol value.

💡 If you do not want this behavior, use the Symbol.for() method.

When we console.log the value of a symbol, it just prints the 'Symbol()' or 'Symbol(label)' but the internal implementation of the symbol is different that guarantees unique values.

Previously, we could only use string and number values as object keys, but JavaScript now supports symbol values for keys as well. However, since symbol can not be represented in literal form, you need to use symbol reference (colorKey_ in the above example_) to access the property value.

Object properties whose key type is symbol are not enumerable. Hence they won’t show up in for-in loop or Object.keys() values.

The reason we had to use @ts-ignore comment in the above example is because of this bug in the TypeScript. To know more about symbol data type in JavaScript, follow this MDN documentation.

undefined

The undefined type represents only the undefined value. It is one of the primitive data types in TypeScript. Its corresponding JavaScript primitive type is undefined. A value of type undefined can only be presented using literal notation since it doesn’t have a constructor.

When strictNullChecks compiler-option is not set or its value if false, the TypeScript compiler allows a variable of type undefined to hold null value as well since they are interchangeable by default.

null

The null type represents only the null value. It is one of the primitive data types in TypeScript. Though it’s a JavaScript primitive value, its runtime type is object which is a bug in JavaScript. A value of type null can only be presented using literal notation since it doesn’t have a constructor.

When strictNullChecks compiler-option is not set or its value if false, the TypeScript compiler allows a variable of type null to hold undefined value as well since they are interchangeable by default.

You can define a variable of type undefined without an initial value and consume it since the initial value of a variable is undefined. However, you must initialize or assign the value of type null before using it just like any other type.

void

The void type represents a value without any type. It is one of the primitive data types in TypeScript. This type purely exists in the TypeScript realm since it does not represent an actual value.

This type is mainly used to represent a function return type when a function does not return any value. But as we know, even if a function doesn’t return anything, the default return value of a function is undefined, hence we can store undefined in a variable of type void.

never

The never type represents a value that never exists. It is one of the primitive data types in TypeScript. This type purely exists in the TypeScript realm since it does not represent an actual value.

Unlike void which represents the return value of a function without an explicit return statement, never represents the return value of a function that can never return a value as shown below.

💡 The comparison between the void and the never type is illustrated in the Type System lesson.

object

The object type represents the values of the non-primitive data types. Which means a value that is not number, string, boolean, symbol, null, or undefined is a valid object. It is one of the primitive data types in TypeScript. This type purely exists in the TypeScript realm since it doesn’t have a fixed data type at the runtime.

💡 In the above example, the assignment of obj with undefined or null is accepted since the strictNullCheck compiler-option is not set.

any

The any type is a special type in TypeScript since it can represent virtually all possible values. It is one of the primitive data types in TypeScript. This type purely exists in the TypeScript realm since it doesn’t have a fixed data type at the runtime.

Since any can represent all the possible values (of any given type in TypeScript), it is called a top type or a supertype. So in nutshell, all types in TypeScript are a subset of any type.

unknown

The unknown type is another top type in TypeScript which acts exactly similar to any with a few minor differences. It is one of the primitive data types in TypeScript. This type purely exists in the TypeScript realm since it doesn’t have a fixed data type at the runtime.

In the above example, we have declared the variable valueA of type any and valueB of type unknown. Since these are top types, they can present any values we throw at them. The unknown type differs from any type when it is assigned to a variable of definite type or when a property is accessed on it.

Since any can contain any value, the assignment of a value of the type any with a variable of type boolean if valid since the value could be boolean at runtime. This however is not possible with the value of unknown since it can’t be trusted by the TypeScript compiler.

Similarly, a property or a method can be accessed on a value of type any since it could be JavaScript object at runtime or it can be called like a function since it could be a function at runtime. This is not allowed with a value of the type unknown since its shape can’t be trusted by the TypeScript compiler.

💡 The comparison between the any and the unknown type is illustrated in the Type System lesson.

Array

The Array type represents a list of items of a given data type. Since Array is composed of items of primitive or abstract types, it is an abstract type.

We can use :Type[] type annotation to represent an array that contains elements of Type type or the :Array<Type> generic notation for the same.

As you can see from the above results, once an array is defined with a specific type, you can not add items to the array of the type other than the specified type.

Tuple

A tuple type represents an array of fixed length and whose elements have predefined data types. However, there is no tuple keyword in TypeScript to represent a tuple. We express a tuple by using an array of types.

In the example above, we have created a tuple student of type [ string, number, boolean ] which means student can hold an array of length 3 with string, number and boolean items in this specific order. If we assign a new value to the tuple that does not satisfy this criterion, TypeScript will throw a compilation error.

#typescript #basics #data-types