Welcome to my second lesson on TypeScript where we'll go more in depth with the built in 'types' that TypeScript includes. If you are new to TypeScript, you should read my initial TypeScript introduction and setup blog here: https://dev.to/vkton115/easy-start-guide-typescript-3ip4
similarly to how javascript has built in types such as
- numbers
- strings
- booleans
- null
- undefined
- objects
- functions
TypeScript introduces some of its own built-in types such as:
- any
- unknown
- never
- enum
- tuple
Inference:
In the last lesson, we learned that we can initialize variables as specific types like so:
let count: number = 123;
this creates a variable with the type of a number set to the value of 123. Because we specified that it was a number, it cannot be reassigned to a different datatype, like a boolean or a string for example.
However, due to inference, we can also write the same login in our TypeScript file as:
let count = 123;
This will achieve the same result and the same variable will not be able to be reassigned to a different datatype. While this does look similar to typing regular JavaScript, the TypeScript compiler will be sure to catch any incorrect reassignments of the variable. There may be some niche situations in which you'd want the variable created to have flexible value types. In these cases, you'd want to utilize any.
ANY
The any typing can be implemented one of two ways. By declaring a variable without assigning it to an inferred value:
let age;
age = 10;
age = 'ten'; //this will work because age was not given a specified type when declared.
Another way to set a typing to any would be similar to setting it to any other type, like so:
let age: any = 10;
age = 'ten';
However, using the 'any' typing goes against what the main functionality of TypeScript. It's merely kept as an option to allow users the ability to declare free-type variables for specific situations where specific typing may not be important or 'code-breaking'.
ARRAYS
In JavaScript, individual elements in an array can be of different types:
let types = [123, 'strings', true];
To specify what type of values the individual elements should be with TypeScript, the format would look something like this:
let numbers: number[]= [1, 2, 3] // this will work because every value in the array is already a number
let age: number[] = [4, 10, '20'] // this won't work because '20' is a string
With inference, the acceptable element types will be whatever types are already present in the array when assigned
let numbersAndStrings = [1, 2, 3, '4'] // this infers that both numbers and strings can exist in this aray
numbersAndStrings.push('hello') // this will work
numbersAndStrings.push(false) // this will error because booleans were not inferred
similarly to how to set a primitive value to an 'any' type, TypeScript arrays can accept any values by initializing it as an empty array.
let anyType = [];
anyType.push(1) //this works
anyType.push('string') // this also works
anyType.push(false) // this works too
CODE COMPLETION
Before we move onto more built-in types, let's talk about one of the key benefits to using TypeScript: Code Completion.
Given a TypeScript Array like:
let numbers = [1, 2, 3]; //inference makes it so all elements are presumed to be numbers
Because TypeScript should now know what type of data each element in the array is, it knows what methods we should have access to. So if we were to iterate through this array, we will receive a list of methods that can be applied to each element after using dot notation like so:
Having this feature is convenient and is one of the ways TypeScript helps with productivity.
TUPLES
Tuples are essentially fixed length TypeScript arrays in which you can specify the type of data that each element index should be. The syntax for TypeScript tuples are as follows:
let person: [string, number] = ['Vincent', 27];
This does a couple of things for us:
1. Tuples make it so we cannot assign the variable to an array of different size than the defined array length.
let person: [string, number] = ['Vincent', 27, 'male'] // error: target only allows for 2 elements
let person: [string, number] = ['Vincent'] // error: target requires 2 elements;
note: using push/pop/shift/unshift methods seems to allow us to bypass this and add/remove values in the array. The reasons for this is unknown to me but at the moment it seems to be a lapse in TypeScripts functionality.
2. Using Tuples also allows us to set the datatype of specific elements in an array.
let person: [string, number] = ['Vincent', 'twenty-seven'] //error index 1 cannot be a string
It is usually best practice to keep the size of the tuples to a minimum (2 elements is usually recommended similar to key-value pair) as it may get harder to distinguish what each value may represent.
ENUMS
Enums(short for enumerated) are a data type that includes values which are predefined. In TypeScript it is initialized with the keyword 'enum':
enum Alphabet {a, b, c}
By default, the first item in the brace's value is set to 0, and each value following it's value will be incremented by 1 so:
a = 0
b = 1
c = 2
You can specify the value of specific item(s) but note that any follow items values will increment by one by default unless otherwise specified.
enum Alphabet {a, b = 20, c}
console.log(Alphabet.a)// 0
console.log(Alphabet.b)// 20
console.log(Alphabet.c)// 21
let letter: Alphabet = Alphabet.b;
console.log(letter) //20
note: adding const to the beginning of the enum declaration will generate a more optimized and cleaner looking code when you run the compiler.
FUNCTIONS
When it comes to functions, annotating your parameters is important to ensure arguments passed in are of the correct typing:
function count(start: number, incrementer: number){
return start + incrementer;
}
Here we are declaring a function named count. its parameters, start and incrementer are both assigned to number types and therefore if you tried to pass in a non-number argument to the count function, you will receive an error.
If you wish to set optional parameters in TypeScript there are two ways.
1. Using default values
function count(start: number, incrementer = 1){
return start + incrementer;
}
count(2) //=> returns 3 (2 + 1)
2. Using '?'
function count(start: number, incrementer?: number){
return start + (incrementer || 1);
}
count(2) //=> returns 3 (2 + 1);
count (2, 2) //=> returns 4 (2 + 2);
Because incrementer could possibly be undefined, we needed to create a condition to handle that case, hence why we set it to 1.
Also note that due to inference, TypeScript knows that the return value will always be a number type. However, in a function in other cases you may want to specify what type of value your return should be, like this example:
function returnNumber():number{
return 7;
}//this will work
function returnNumber():number{
return '7';
}//this won't work
related configs:
noUnusedParameters - when set to true, if a parameter is never used within a function, it will show an error.
noImplicitReturns - when set to true, it will error if a function has a code path that does not explicitly return in a function.
noUnusedLocals - when set to true, it will error if there are any unused variables. This includes variables declared within functions.
OBJECTS
When it comes to JavaScript objects, we're accustomed to being able to add properties with dot/bracket notation like so:
let obj = {};
obj.name = 'Vincent';
obj.age = 27;
console.log(obj) => // {name: Vincent, age, 27}
However, in TypeScript, we need to define the body of the object before we can change its properties as we will not be able to add/change properties that do not match the object that we defined.
let contactInfo: {
name: string,
phone: number,
fax?: number
} = {name: 'Vincent', phone: 123_456_7890}
note: numbers in TypeScript can be split with an underscore(_) to segment it
As you can see, we initially defined the structure and typing of each key's value in the body of the object. The fax is set to optional with the '?' so therefore we do not need to include it when we assign the initial value of the object. Using the '?' is generally not recommended as it can cause unforeseen errors when compiling, however in this case it makes sense as not every person may have a fax machine.
And finally since we defined the types of each key's value, they can be reassigned as long as they are being reassigned to the same datatype.
contactInfo.phone = 987_654_3210 // this is an ok reassignment
contactInfo.phone = "(123)-456-7890" //this won't work because it expects a number and not a string.
CONCLUSION
Thank you for taking the time out to read this TypeScript tutorial. I hope I was able to help you understand the standard built-in types that TypeScript provides. Stay tuned for more information on more advanced types.
Top comments (0)