This article covers all that you need to get started with TypeScript. Before we jump into understanding what typescript is, I believe it is extremely important to understand the concept of typing.
Static Typing
In static typing, the programmer needs to specify the type of the variable explicitly. In statically typed languages such as c++, java etc.., the types are checked in compile time
. Trying to assign a different type to an already type assigned variable will throw an error in the statically typed languages. Let's see an example with a c++ snippet
int a = 10;
a = "hello"; // error: invalid conversion from 'const char*' to 'int'
From the above code snippet, we can infer,
- In static typed languages, the type of the variable should be assigned while defining a variable
- The type of the variable
a
is integer throughout the program - Trying to assign a different type to the variable
a
throws an error - The type is checked and the error is thrown during the compile time only
Dynamic Typing
In dynamic typing, the programmer does not need to specify the type. In dynamically typed languages, the type is checked on the fly i.e., during execution ( runtime ). Dynamically typed languages include Javascript, python etc.., Let's see a javascript code
var a = 10;
console.log(a) //10
a = "hello"
console.log(a) //hello
The above code snippet does not throw any error as the JS engine checks the type during runtime.
Now that we are clear with typing, let's dive deep into TypeScript
What is TypeScript?
We know that JavaScript is a dynamically typed language. Typescript acts as a static type checker
for JavaScript. Typescript is a superset of Javascript. i.e., Any valid JavaScript code is again a TypeScript code, but TypeScript acts as an extra layer of defense. The code that is going to be executed in the browser is anyway javascript code.
Typescript compiles into javascript code. Thus the types are checked during compile time.
Why TypeScript?
- Having types checked during compile time helps developer write better code. Developers can make sure that things don't fail during runtime. Consider the above code snippet in
.ts
file
var a = 10;
console.log(a) //10
a = "hello" // Error: cannot assign `string` to `number`
The important thing to understand here is that trying to log a
will eventually log "hello", as typescript compiles to javascript, but it gives a compile time error in the IDE
- Increase readability and understandability of the code. TypeScript code acts as a documentation for the next developer.
const addTwoNumbers = (x: number, y: number): number => {
return x + y;
};
Let us ignore the syntax for now, but just by looking the above code, we can infer that, the above function takes two numbers
and returns a number
.
Assigning Types to Variables
Primitive datatypes
let a: number = 10;
let b: string = "hello world";
let c: boolean = true;
The above code snippet means that the variables a, b and c are strictly number, string and boolean
types respectively. They cannot be assigned values that are not their respective types.
Let's play around with the code to understand what happens when we try to assign them to values that have different types.
As soon as we write the second line, the IDE throws an error. This way it is really easy to understand the error instead of waiting to throw an error during runtime.
Non primitive Datatypes
Arrays
For Arrays, the typing goes like,
const numArray: number[] = [1,2,3];
const stringArray: string[] = ["hello", "hi"];
Let's try having string values in the numArray,
Objects
Let's consider an object, to define the type of an object, let's use type
annotation.
type User = {
name: string;
age: number;
isMarried: boolean;
}
const user : User = {
name: "abc",
age: 22,
isMarried: true
}
In the snippet above, we are assigning the type User
to the user object. Thus trying to assign values of other types will throw error.
Another interesting thing here is that, in JS, trying to access a property that does not exist in the object returns undefined. Let's see, how this behaves in a .ts
file
any
Typescript also has a type any
, which we can use when we don't want to get type checking errors. Basically, the type any
allows a variable to have any datatype.
The above code snippet with any
type does not throw any error.
Assigning Types to Functions
Like how we assign types to variables, types can be assigned to parameters and returning value of a function as well. This way, we can restrict the type of the input a function takes and the type of the value a function returns.
Let's write a function that calculates sum of two numbers, This function takes two numbers as inputs and returns the summed value. Let us convert these restrictions to code. I am hereby using arrow function notation,
const addTwoNumbers = (x: number, y: number): number => {
return x + y;
};
addTwoNumbers(2, 5) //7
Let's see how the code works when we try to pass a string value as input,
A normal JS code without type restriction would not throw error in the above case and result in 2hello
Trying to return a string type also throws an error,
Optional Properties
Some properties of an object could be optional. In those cases, we can use ?
operator implying that particular property could be optional. So no error is thrown in case the object is not present.
type Name = {
firstName: string;
lastName?: string;
};
const getFullName = (name: Name): string => {
const lastName = name.lastName ? name.lastName : "";
return name.firstName + lastName;
};
getFullName({ firstName: "sruthi" }); //sruthi
getFullName({ firstName: "sruthi", lastName: "Ragupathy" }); //sruthiRagupathy
In the above code snippet, the function takes an object that has properties firstName and lastName and returns the fullName concatenating firstName and lastName. This does not throw any error if we dont give a property lastName as we have defined it as an optional type using ?
.
Union Types
Typescript also allows a variable to have one or more datatypes. To combine different datatypes for the same variable, we can use |
operator
const getRollNumber = (rollNumber: number | string) => {
return rollNumber;
}
getRollNumber(352); //352
getRollNumber("352"); //"352"
getRollNumber(true); //Argument of type 'boolean' is not assignable to parameter of type 'string | number'.ts
Interfaces
Interfaces are another way to define the type of an object. The user object with interface
notation looks like
interface User {
name: string;
age: number;
isMarried: boolean;
}
const user : User = {
name: "abc",
age: 22,
isMarried: true
}
Difference between interface notation and type notation is,
- interfaces are extendable while types are not
Literal Types
We can not just specify datatypes for variables, we can also assign specific values to a variable.
let x: "hello" = "hello";
x = "hello";
x = "world"; //Type '"world"' is not assignable to type '"hello"'
x = 1; //Type '1' is not assignable to type '"hello"'
We can also assign one or more values for a variable using union.
Let's consider a function,
const getFruit = (fruit: "mango"|"apple"|"orange") => {
return fruit
}
getFruit("apple"); //apple
getFruit("kiwi"); // Argument of type '"kiwi"' is not assignable to parameter of type '"Mango" | "Apple" | "Orange"'.
Typeguard
We have seen that we can use more than one datatypes for a variable using unions, Let's consider the example
We see that + cannot be applied to types number | string. Here comes the picture of Typeguard.
Typeguards are the special checks through which we can narrow down the possibility of a particular value or datatype assigned to a variable.
The above issue can be resolved using typeof
Typeguards
const getNextRollNumber = (rollNumber: number | string) => {
if (typeof rollNumber === "number") {
return rollNumber + 1;
}
return Number(rollNumber) + 1;
};
getNextRollNumber(352); //353
getNextRollNumber("352"); //353
Here we have come to the end of the blog. I have covered almost everything to understand the basics of TypeScript. Hope you find it helpful.
Connect with me on Instagram, Twitter and Linkedin
Happy Coding!!