Learn about how Type Annotations in TypeScript works? Its advantages over JavaScript in improving code readability, maintainability and throwing compile time errors, if type of values assigned vs defined do not match.
Type annotation helps us to define explicit types to variables, functions, objects, etc. To explicitly mention a Type in TypeScript we need to use ': <type>'
after an identifier which in turn will help TypeScript compiler to keep a control on the values that can be assigned to the variable and if we try to assign another type of value to defined variable it will throw a compile time error. More advanced code editors will highlight the error for us even before we compile.
// Example of using string type annotation
let firstName : string = 'Angelina';
TypeScript will hold the information that firstName
is a string type variable so, if we try to assign a different type of value to firstName
let’s say number 10. TypeScript compiler will throw and error "Type 'number' is not assignable to type 'string'
.”.
Advantage of using Type Annotations in TypeScript
If we are using any built-in functions of the JavaScript language, example firstName.upperCase()
. It will give a run time error in JavaScript if the value in variable is number. But, in case of TypeScript the error will be called out in compile time only. So we can save our application from unexpected exception.
- TypeScript helps us to control the type of value a variable can hold.
- Saving us from run time error over value type mismatch
- Built-in function of JavaScript will not break due to type mismatch. We will not get errors like
"Property 'length' does not exist on type 'number'."
.
Type annotation for variables
lets look at the basic variables syntax for defining type annotation. We will look at difference from JavaScript to TypeScript for better understanding
// Using JavaScipt
let carName = 'Audi';
const MAX_OUTPUT = 10;
// syntax for annotation for variables in TypeScript.
<let|var|const> <variable name> : <variable type>;
let carName : string;
carName = 'Audi';
const MAX_OUTPUT : number = 10;
The major difference is the ":"
symbol which defines the type of variable it can hold, helps us to control the values that can be set in a variable during program execution.
If we try and assign a new value to the variable 'carName'
, TypeScript will check if the variable is assigned the right type of value defined during variable declaration, if not it will throw and error.
// assigning new value BMW to carName
carName = 'BMW'; // no error since the type of value we are setting is still a string.
// assigning new value 10 to carName
carName = 10; // error is generated "Type 'number' is not assignable to type 'string'.".
Type annotation for objects
Most of the time we will be using complex object structure to store data, calling multiple function to process data and take actions on user inputs as well as validate response received from an api or sending data to backend server to store user inputs.
We can define custom types using ‘type’ keyword
lets say we want to keep all name related variables as string we can define a custom type name and then use it across application.
// defining a type name which is of string type.
type name : string;
// using defined type 'name'
let firstName : name ;
let lastName : name ;
If you look closely we have defined a type 'name' as 'string'
type and used it to define two variables which are both of name type. TypeScript will infer it and say that 'firstName'
and 'lastName
‘ are of both name type which in turn is a ‘string’ type so any value stored in these variables will be of only string type. This concept might not look very useful at first but helps us a lot when we try to create more complex object structures by composing multiple objects.
Let’s take an example of more complex object which has multiple data types and are composed of two object.
// Define an object of student information type
type studentInfo {
name : string ;
age : number'
}
// Define and object of marks that the student has achieved.
type marks {
subjectName : string;
marksAchieved : number'
}
// Define an object which will hold data for student and the marks achieved by student.
type marksAchieved {
student : studentInfo;
marksAchievedInEachSubject : Array<marks>;
}
Now, we have the flexibility to add or remove any variable as per our requirements from marks or studentInfo
object as the application grows without changing the marksAchieved
and still keep control on the data the object can hold.
Type annotation for Function arguments and return type
Type annotation in TypeScript is a little tricky for function. Consider the function as a blue print only we are not concerned about the internal logic of function but only the input and output.
Function is divided into two parts.
- The incoming information which we term as arguments that are getting passed while we call the function.
- The response the function provides, which can be an object, variable or nothing i.e. void (a function which only process data but do not return anything).
We will see each concept one by one an then combine them to look at how a function looks in TypeScript definition.
function addNumber ( a , b ) {
let result = a + b;
}
console.log(addNumber ( 10 , 20 ) ) ; // output : 30
console.log(addNumber ( 10 , 'a') ) ; // output : 10a
Well this was not expected from the user of the function to pass a string
value in addNumber
function. No errors were generated but we created this function to add two numbers not string.
This is the very issue that TypeScript tries to solve. Lets take the same function and rewrite it using Type annotations in TypeScript.
// defining a function in TypeScript to add tow numbers.
function addNumber ( a : number , b : number ) {
let result = a + b;
}
console.log(addNumber ( 10 , 20 ) ) ; // output : 30
console.log(addNumber ( 10 , 'a') ) ; // output : Argument of type 'string' is not assignable to parameter of type 'number'.
Summary
- ‘Type’ helps us to control the values that can be set inside a variable, object or passed to functions.
- TypeScript will generate compile time error if we try assigning different types, saving us from errors at runtime optimizing developer efforts.