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 whileobject
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
, octal0o
or the hexadecimal0x
prefix to represent an integer value, for examplelet count: number = 0x65
for the value of decimal101
. 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 aboutsymbol
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 thenever
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 theunknown
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.