๐ชดBase Types
Digging deeper into TypeScript.
Primitive Types
In JavaScript, null
, undefined
, boolean
, number
, string
, etc. are some of the important primitive data types. Let's look at the core basic primitive types in Typescript:
Numbers
It is important here that the type definition for a 'number' starts with a small-case 'n'. If we use 'Number' instead of 'number', we would be pointing to the object
Number, and not the type
'number'. Same goes with 'string' and 'boolean'.
Strings
Please use 'string' instead of 'String' for reasons stated above.
Boolean
Please use 'boolean' instead of 'Boolean' for reasons stated above.
Complex Types
Moving ahead from the primitive data types, we will have a look at the complex data types, mainly: arrays
and objects
.
Arrays
Objects
Typescript has a special type, called "any"
, which allows us to declare variables without telling typescript what type of values we want in that variable. We do not need to explicitly provide this type, but we can if we would like to. But this actually defeats the purpose of using Typescript in the first place.
We can define the "object type definition
" for an object in Typescript:
To store an array of objects with object type definition, we can do it as shown below:
Type Inference
By default, if we do not provide the type of variable we are initializing, Typescript tries to infer the type by itself, and gives a warning if we assign a different type to that variable, without is explicitly stating the type of variable we are defining.
Union Types
A union type
is a type definition that allows more than one type to be assigned to a variable.
Type Aliases
We use type aliases to avoid type definition duplication. We can assign and use aliases to type definitions to avoid such code duplication. We define an alias using the type
keyword, which does not exist in standard Javascript, but is defined in Typescript. We then provide a type name, which we then provide type definition to. This makes our code more concise and easier to maintain.
Functions & Function Types
Functions returning values
Just as we provided type definition for variables, we can provide type definitions for parameters of a function. Based on these parameter type definitions, Typescript can infer
the return type, and internally set the function return type definition to that type.
Consider the following code snippets, where both the functions have the same return type:
"void"
type definition
"void"
type definitionConsider a function where we just log some data to the console, and do not return any value from the function. In that case, Typescript will infer a special type called "void"
. We can explicitly define the function type definition as well with "void"
. Void basically means it is comparable to null and undefined, but it is limited to be used only to functions, which ideally means that the function never returns anything.
Generics
Consider the following example, where we insert a value at the beginning of an array, without altering the original array, and we return a new array with the new value inserted at the beginning of the original array:
Problem
It is a useful helper function, which takes in any type of array and a value, and inserts the value at the beginning of the array. But the issue here is, we want the array and value to be of the same type, but at the same time, this helper function should be flexible enough to allow other types also to be used in this function.
Ideally, it would be useful if this function worked with arrays of number, strings, etc, but not a mixture of arrays with strings and numbers (which is what is happening with the type definition of "any").
Since Typescript does not know the type of values inside the array, we could call a string function on an array value that is of type number. This is wrong, since it would give an error during runtime, but typescript does not know this, and hence does not throw an error.
Hence, we have Generics
, that will help make the insertAtBeginning
function into a generic function.
Using Generics
For using generics to solve the above mentioned problem, we have a special syntax. Before the start of the parameter brackets, and after the function name, we add angular brackets
or <>
. Inside these brackets, we will define a generic type that will only be available within this function. Typically it's called "T"
, but we can use any identifier. Now we can use this type in our function, including the parameter list. Have a look below:
With this, we tell Typescript that the type of array
is T
(which can be array of strings or numbers or any, etc.), and the value
should also have the same type (i.e, of type number or string or any), and finally the function will also have the same return type T
, which should again be of the same type as array and value.
So now, if we try to use string functions on the returned value in numArr
, Typescript will throw an error!
To read more in-detail about typescript with examples, have a look here.
๐คฏ Generics everywhere?!
We are working with generics all the time, one of the most prominent examples is an array. Consider the following example array:
Here, the type is inferred, but we can explicitly define the type:
Here "number[]
" is just TypeScript notation for saying "this is an array of numbers". But number[]
is just syntactical sugar. The actual type is Array
. All arrays are of type Array
. But since array type only makes sense if we also describe the type of values in the array, Array is actually a generic type.
Here we have the angle brackets (<>
) again! But this time NOT to create our own type, but instead to tell TypeScript which actual type should be used for the "generic type placeholder" (T
in the previous section). We can use these in the previous example as well:
So we can not just use the angle brackets to define a generic type but also to USE a generic type and explicitly set the placeholder type that should be used - sometimes this is required if TypeScript is not able to infer the (correct) type.
Last updated