Just enough Typescript to build Projects.
Tags: typescript, tutorial, codenewbie, webdev
Published: 2023-07-11 10:49:02

## What is the point of using TypeScript ? 
JavaScript is a **dynamically typed language** meaning **type checking is performed at runtime** or at the time of execution. 

JavaScript allows accessing values which aren't present leading to unexpected bugs.

```js
const person = { name: "John Doe", id: 1 };

console.log(person.email) // <- undefined
person.name.toUppercase() // <- will throw TypeError
``` 

TypeScript was created to solve these type of problems by adding static type checking to JavaScript.

Think of JavaScript as a person which doesn't provide feedback until you Beat the s- I mean ask it. The feedback provided however is not much in-depth such as where might the error be until you console log it like above.

TypeScript is a **typed superset of JavaScript which provides static type checking** (type checking is performed at compile time) to catch potential bugs before runtime. It adds **type safety** to your JavaScript code.

With TypeScript, The above code will now throw an error in the IDE before runtime.

![TypeScript Error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cvfnb4p4siaa8qm4qrli.png)

Typescript is basically a more wiser version of JavaScript which helps you catch a lot of errors including typos, uncalled function (Math.random * 6), etc.

## TL;DR 
types + Javascript = Typescript.


## Basic Types 
Before using Typescript we need to know about JavaScript types and some special TypeScript types.

Here are a bunch of them - 
1. `string` 
2. `number` (there's no int or float data type in JavaScript)
3. `boolean`
4. Arrays (datatype[] or `Array<datatype>`)
5. object ({}) 
6. `any` (NOTE :- This removes the type safety provided by TS, meaning you will be back to the same old JavaScript for that particular variable)
7. undefined 
8. void
9. never
10. unknown
11. Union Types (combination of two or more types)
12. Enum 

and more.

## Type Annotations and Inference

TypeScript allows you to optionally specify the type of variable while declaring it. 

```js
let name: string = "senbo";
let count: number = 0;
let isEven: boolean = true;
let array: number[] = [1, 2, 3, 4, 5];
let obj: { a : number; b : number; c?: number } = { a : 10, b : 20 
let age: number | string = 20; // union type, age is either a number or string
let alignment: "left" | "centre" | "right"; // Union of literal types
};
```
These are called **Type Annotations**.

In the example of object, we use `;` separate the properties and declare a property optional by adding `?` after its name.

But this is redundant as TypeScript can automatically infer the type of variable based on assigned value. 
![Type Inference](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3doonrn1ivdz93e5xnib.png)

This is called **Type Inference**.

## Functions in TypeScript

While declaring a function you can add Type Annotations to parameters and return type, so that arguments to that function gets checked.

```js
function add(a: number, b: number): number  {
  return a + b;
} 
```

In the above function, a and b are assigned the type `number` as well as the return type which comes after the closing parenthesis of parameter list, note that the return type can be inferred by typescript so it is not necessary to write always. 

Here are some more examples 
```js
function print(name: string): void {
  console.log(`Hello ${name}`);
}

function sum(...numbers: number[]): number {
  return numbers.reduce((acc, curr) => acc + curr);
}

function printLength(item: string | string[]) {
  if (typeof item === "string") {
    console.log("Length:", item.length);
  } else {
    console.log("Lengths:", item.map(str => str.length));
  }
}
```

The first function, `print`, simply console logs the string, hence the return type is void.
The second function, `sum`, uses the [Rest parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters) syntax, allowing it to accept an indefinite number of arguments so we use array of numbers. 
You may want to revisit [reduce](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce) function.
and in the last function, `printlength`, item is either a string or an array of string, inside the function we use `typeof` to check its type. If it is a `string`, we simply log the length of the string otherwise if it is an array, we iterate over each string in the array and log their lengths. This is called **Narrowing**.

## Type Aliases 

It is a name for a type, It is used to create reusable types or if you simply want to separate writing types for convenience.

You may capitalize type aliases name to differentiate them from variables and functions.

```js
type Person = {
  name: string;
  age: number;
};
 
function greet(p: Person) {
  console.log(`Hi ${p.name}, you are ${p.age} years old`);
}
 
greet({ name: "John Doe", age: 100 });

// Some more examples
type ID = number; 
type Name = string;
type Age = number | string;
type NaturalNumbers = number[];

type Body = {
  height: number;
  width: number;
  location?: string;
  readonly name: string; // This property cannot be re-assigned.
}
```

We can use type aliases to create **function type expressions**.

```js
type func = (a: string) => void; // function type expression

function greets(name: string, callback: func) {
  callback(name);
}

greets("John Doe", function (name) {
 console.log(`Hi ${name}`);
});
```

The above type `func` means a function with one parameter of type `string` and returns nothing.

## Interfaces

Interfaces are another way to name an object type. They are similar to Type Aliases but have some distinctions which we'll talk about later.

Syntax
```js
interface Book {
  title: string;
  author: string;
  readonly pageCount?: number;
}

const book: Book = {
  title: "The Great Gatsby",
  author: "F. Scott Fitzgerald",
};

interface AnotherInterface {
  name: string;
  func: (a: string) => void; // describe a function inside interface
  func2(a: string): void; // another way to describe a function
}

// This is function type, functions in JavaScript are objects which can be called, and we can also add properties to our functions.
interface MathOperation {
  (x: number, y: number): number;
}

const add: MathOperation = (x, y) => x + y;
const subtract: MathOperation = (x, y) => x - y;

// Its type aliases equivalent
type MathOperationType = (x: number, y: number) => number;
```
Some key differences between Types and Interfaces

Types aliases do not support declaration merging while interfaces do.

Declaration merging is adding new properties to an existing interface.

for example, 
```js
interface Object {
  a: number;
}

interface Object {
  b: number;
}

function printobj(o: Object) {
  console.log(o.a);
  console.log(o.b);
}
```

Both Interface and types can be extended but have different syntax.

You can read more about these distinctions [here](https://stackoverflow.com/questions/37233735/interfaces-vs-types-in-typescript).

You can use whatever you like, I generally use interfaces for objects and types for everything else.

## Generics

lets say you wanna create a function that accepts an argument and returns it.
```js
function identity(arg: any) {
  return arg;
};

let num = identity(5);
```
This works fine but the issue with this is we lose all our type definitions for the return value of the function. If we pass in an argument of type `number`, the function returns the same argument but with type `any`.

![Type is any](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yp2d7qouibhf7e3g8xeb.png)

By using generic this problem can be solved.
```js
function identity<T>(arg: T): T {
  return arg;
}

// Two ways of consuming generic functions
let num0 = <number>identity(5); // explicitly passing the T parameter
let num = identity(5); // let the compiler infer it
```

![Type is number](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4xwzsl7461fnu9zq4t7v.png)

The `T` in the angle bracket is called the Type Variable, you can name it whatever you like.

Generics are used to create reusable components that work with different types of data.

Let's say now we want to pass an array of different types and return it
```js
function identity<T>(arg: T[]) {
  return arg;
}
```
Notice we don't have to specify the return type as the compiler can infer it.

If we want to have a generic type for types with a length property such as string and arrays. We can use something called a constraint.
```js 
function identity<T extends { length: number }>(arg: T){
  return arg.length;
}
```

In similar way we can create generic interfaces.
```js
interface Box<T> {
  value: T;
};

type NumberBox = Box<number>;
type StringBox = Box<number>;
```

## Tuples

Tuples are array but with a pre-defined length and types for each index.

Syntax
```js
type FirstTuple = [number, string];
type SecondTuple = [number, string, boolean];

const firstTuple: FirstTuple = [1, '2'];
const secondTuple: SecondTuple = [1, '2', true];
```

FirstTuple is an array of fixed length 2 with index 0 being a number and index 1 being a string. if we try access element past index 1, TypeScript will throw error.


![TypeScript Error Image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whj3ucxuvkarptjz8z4o.png).

## never

Type when function **never** returns a value, it is similar to void but it is used when function throws an exception or if a function enters an infinite loop.

```js
function throwError(message: string): never {
  throw new Error(message);
}

function infiniteLoop(): never {
  while (true) {
    // ...
  }
}
```

## Non-null Assertion Operator (Postfix !)

It is used to tell the compiler to assume that a value is not `null` or `undefined`, even if typescript thinks it could be nullable.

```js
function func(arg?: number) {
  console.log(arg!++);
}
```

## Type Assertions

Type Assertions are way to override the type inference and explicitly set the type. 

For Example 
```js
const btn = document.getElementById("my_button") as HTMLButtonElement;
```

TypeScript thinks that getElementById will return some kind of HTMLElement, but you can override this by using the `as` operator.
 


Thanks for reading, I tried to condense as much as examples possible and tried cover most frequently used types.