Learning TypeScript Part 1
===

---
###### tags: `TypeScript`
# Install TypeScript
- Visit [TypeScript](https://www.typescriptlang.org/download) and scroll down.
- If you only want to install per project, then run `npm install typescript --save-dev`
- Or you can install it globally by running `npm install -g typescript`
- For macOS user, you might encounter error like "permission denied", please run `sudo npm install -g typescript`, then enter your password.
---
# Type Annotation Basics
### string, number, boolean
#### string
- Add `:Type` after the variable name, this also called **Type Annotation**
```typescript
// JS
const a = "Cool";
// TS
const a: string = "cool";
```
- TS doesn't allow to reassign to a different type, but a value of same type
```typescript
let myString: string = "Hello world";
// Can't reassign to a different type
myString = 100;
// Can reassign to a value of same type
myString = "Goodbye world";
```
- In VScode, it will show error.

- If there's a typo, it will show error as well.

---
#### number
- Rules are the same as above.
```typescript
let numOfCars: number = 10;
// Can't reassign to a different type of value
numOfCars = "ten";
```
#### Boolean
- Rules are the same as above.
```typescript
let isDadHome: boolean = false;
// Can't reassign to a different type of value
isDadHome = "false";
```
---
### Compiling TypeScript
- Run this command in terminal `tsc var.ts` (If you already installed typerscript globally, this should work).
- You will find that there will be another file with same file name, but with different language.

---
### Type Inference
- **Type Inference** refers to the typeScript compiler's ability to infer types from certain values.
- TypeScript can remember a values's type even we did not provide a type annotation, and it will enforce that type moving forward.

---
### The any type
- `any` is an escape hatch, it turns off type checking for this variable.
- Do not use this if unnecessary.

---
## Recap
1. Type annotation : When we try to specify the type of a value.
2. If we don't specify a type, it will be `any`.
3. Once you specify a type, if you want to reassign the value, it should be same type, otherwise TS will show error.
---
# Functions
### Function Parameter Annotation
- We need to specify the type for parameters, otherwise it would be type `any`, if the type is `any`, even we want to have a number as parameter, but we give a string or boolean when we call `square()`, TS won't show any errors.**Better specify the type**

- Once we specify the type, TS will show error immidiately.

- If the method was wrong, TS will show error as well.

- We can have multiple parameters, but if we did not provide enough parameters, TS will show error.

---
#### Default parameters
- We add a default value after annotation so that TS won't show any error if we did not provide enough parameters.

---
#### Return type annotations
- TS will show what is supposed to return, in this example, it will return value of number, but it's good to specify at the beginning of the function so that whoever is going to review the code will get the idea.


- TS is smart to figure out which type is going to return if the function contains different types.


---
#### Anonymous Function contextual typing
- We've talked about if we don't specify type, it would be `any`, but what if it's an anonymous function?
- TS is smart enough to read the context, in this example, we have an array with strings, so it showed string immidiately with showing an error.
- We could specify this way as well `animals.map(animal:string =>{...})`.
- Gental reminder, if we use methods that don't apply to string, TS will show error.

---
#### The void type
- `void` type is when a function doesn't return anything.

- Just like we have said above, it's always clear if we specify in the beginning.

- If we don't specify `void`, but we ended up like return something, it would show error.

- **void** returns `undefined` or `null`.
---
#### The never type
- Usualyy we use `never` to annotate a function that always throws an exception, or a function that never finishes executing.
- For example: A while loop or a function that just throw a error.

- In above examples, if we try to return something, TS will show error.
- How do we know if we need to anootate `void` or `never`?
- `void`: If we do not want this function returns anything.
- `never`: If we want the function is never finishing executing or always throw an exception.
---
# Object Types
- Just like functions or variables, we need to declare type first, and if we provide a different type, TS will show error.
- First, we delcare an object `person` as an argument and annotate its type.
- When we provide a number for the last, TS shows error.

- Let's change number to string and add `void` to be more specifc.

- We can annotate a function parameter type to be an object, we can also do the same thing for a return type or a variable.
- First one was variable, we declared a variable called `coordinate` and following the column, we annotated the types by adding `{x: number; y: number }`, then made it equaled to the actual value `{x: 45, y: 90}`
- Same rule goes to the second one, **remember that it's an annotation behinds the column.**

---
## Express properties
- If we pass an object as an argument, TS won't allow us to add extra element.

- But if we declare a variable and assign the object, then pass the variable as an argument inside the function, TS won't show error, see the second `printName(man)`.

> The team behind TS might think the behavior of first one might be an mistake, probably added by accident, but it make sense if we consider the pattern here, TS is strick, so if we **annotated types first and then add more**, I am not surprised TS shows the error.
---
## `type` as alias makes life easier
We can declare an object by using a much easier way in order to minimize typing duplicated code like this, we can see there're 4 `{x: number, y:number}`.

Using `type` alias to define type first, then we can replace from duplicated code to alias.

---
## Nested Objects
If we define types inside function like this, it's not readable, hence, it's better define our type first like the screenshot.
```typescript
function calculatePayput(song:{title: string; artist: string; numStream: number; credits: {producer: string; writer: string}}) ...
```

## Optional property
Make an property optinal, we can just add a question mark before column.

---
## Readonly
If we add `readonly` property before a key, it will not allow us to change afterwards.

---
## Intersection types

- Step 1: Define individual type
```typescript
type Sex = {
gender: string
}
type Age = {
age: number
}
type Country = {
country: string
}
```
- Step 2: Intersecting types
```typescript
type UserProfile = Sex & Age & Country;
```
- Step 3: Create object

- Want to add more properties, just add `&` with `{}` and add properties inside of it.

---
# Array type
- when we want to define a type for array, we need to specify types and add an empty braket.
```typescript
const stringArr: string[] = [];
const numArr: number[] = [];
const booleanArr: boolean[] = [];
```
- when we annotate a type of that array, we can only store values with same type, otherwise TS will show error.

- We can design our own type and make it as a type.

- Another way of annotating types

### Notice:
This is an array will have a type of `never`, and it will not allow us to assign any type of values.
```typescript
const userName: [] = [];
```
---
## Multidimentional Arrays
With more then one arrays, we can specify like this:
```typescript
const demo1: string[][] = [
["x", "y"],
["x", "w"],
];
const demo2: number[][][] = [[[3]]];
```
---
# Union Types
Union types allow us to give a value of few different possible types.
Using the single | (pipe character) to separate the types we want to include.
If we assign a value that does not inclued, TS will show error.

We can also use union type for object.

---
## Narrowing the type - function
Since we can use union type to annotate multiple types, but when it comes to a function, Ts will show error if we try to apply methods that can only be available to string or number.
The code below shows error becuase price could be a number or string at the moment and TS doesn't know which types that price is.

Here we try to apply `replace()` method to price, but like we said before, TS doesn't know what type price is, so we are not allow to use the method.

Here we add a condition to check the type first, if `price` is `string`, then we can convert `price` to a `number`, and TS is smart enough to be sure that when we try to `return price * tax`, the price here is a `number`.


---
## Union types & arrays
An array could contain multiple types, but we want to avoid using `any`, so here comes union types to solve the problem.

- `randomStuff1` is valid, because we grab both types by using `()` and joint a `[]`, this means any value of a number or a string is acceptable.
- `randomStuff2` is invalid, because it should only be an array of string.
- `randomStuff3` is invalid, it should only be an array of number
- `randomStuff4` is invalid, it should be either an array of number or an array of string.
---
## Literal types
Literal types are not "types" but the values themeselves.
```typescript
let zero: 0 = 0;
let hi: "hi" = "Hi";
```
But it can be useful when it combines with union type.Here we define that answer should be either `yes`, `no` or `maybe`, answers that out of the scope will be an error.

---
# Tuple
Tuples are a special type exclusive to TypeScript. They are arrays fixed lengths and ordered with specific types - like super rigid arrays.
```typescript
const tuple1: [number, number, string] = [23, 32, "Hello"];
const tuple2: [string, string, string] = ["hello", "World", "Hahah"];
const tuple3: [boolean, number, string] = [true, 23, "Ohhhh"];
```
If we did not provide the right length or type, TS will show error.

---
## Weird thing about tuple
As we know that Tuple is an array with fixed length and type,it allowed us to `push()` or `pop()` new elements, but it's not allowed to change element.

---
# Enums
Enums allo us to define a set of named constants. We can give these constants numeric or string values.
```typescript
enum OrderStatus {
PENDING,
SHIPPED,
DELIVERED,
RETURENED,
}
const myStatus = OrderStatus.DELIVERED;
function checkDeliver(status: OrderStatus) {
return status === OrderStatus.DELIVERED;
}
checkDeliver(OrderStatus.DELIVERED)
```
Usually if we don't assign a value to it, it will start as `0`, but overall, we can assign value to it.

```typescript
enum {
UP = "up",
DOWN = "down",
Left = "left",
RIGHT = "right"
}
```
## Enum behind the scene
We can use [TypeScript Playground]((https://www.typescriptlang.org/play)) to check what's behind the scene when we use `enum`.

Some people don't like the complexity, but we can see that in `JavaScript` it generates the number for us, here we can add `const` before `enum` syntax, the result of `status` became the number we've seen above.

---
# Interface
`Interface` is only for `Object`, although it's similar with `type`, but it can't be used for `union type`, syntax as below:
```typescript=
// type
type Point = {
x: number;
y: number;
}
const point: Point = {x: 1232, y: 3445};
// interface
interface Point {
x: number;
y: number
}
const point: Point = {x: 3333, y: 345};
```
## Readonly and optional property
We add `readonly` syntax to show that the property cannot change; And add `?` to show that the property is optional.
```typescript=
interface UserProfile {
readonly id: 1;
firstName: string;
lastName: string;
nickName?: string;
}
const user1: UserProfile = {
id:1,
firstName: "Tom",
lastName: "Hardy",
nickName: "Tommy"
}
```
If we try to change id number, TS will show error, and since `nickName` is optional, if we remove `nickName`, TS won't show any error.

Try to change `id` number.

## Adding methods
There are two ways to add methods in a interface, but make sure you don't add any arguments since we did not define in the `interface`.
```typescript=
interface UserProfile {
readonly id: 1;
firstName: string;
lastName: string;
nickName?: string;
sayHi: () => string;
sayGoodBye(): string;
}
const user1: UserProfile = {
id:1,
firstName: "Tom",
lastName: "Hardy",
sayHi: () => {return "Hello"},
sayGoodBye(){return "Bye bye"},
}
```
## Adding parameters

Let's run `tsc [file name]` to convert TS to JS and `console.log()` to see the result.


## Reopening interface
When using `interface`, we can extend properties withput getting error, but when using `type`, TS will show error.
We can't extend properties with `type`.

We can extend properties with `interface`, but once we extended properties, we need to make sure we've got all types included.


## Extending types
We've seen that using `interface` can kind of extend types, but using `extend` syntax can actually **inherit** all types along with its own type.

## Extending multiple interface
We've seen that we can extend interface, but the truth is that we can extend more than 1 interfances.

## Differences between `interface` and `type`?
Key differences between type and interface:
1. Interface can only describe the shapes of objects.
2. Interface can reopen and add on more types.
3. Interface can `extends` other interface. type needs to use `&` as union type.
---
# TS compiler
### Generate config file
- Run `tsc --init` to generate a `tsconfig.json` file.

### Compile to js file
- Run `tsc [fileName].ts` to compile to a `JavaScript` file.
### Watch ts files
- Run `tsc -w [fileName].ts` or `tsc --watch `
- After watching the file, we can keep watching if there's any changes, it will re-complie if there's no errors.
- If there's an error, terminal will show it as well.


### Working with multiple ts files
- We can run `tsc [fileName].ts` with different files one by one to compile ts files into js files, we can also run just `tsc` to complie all files once for all.
### Specifing ts files to compile
- Since running `tsc` will compile all the files, including files that might not need to be compile, we can specify an allowlist of files to include in the program in tsconfig.json.
- This need to be the top level option, meaning this won't inside the `compilerOptions`.
> 
- Here I specified that only to compile `index.ts` and `index2.ts`.


- Another way of asking ts to compile specific files is to use `include` and `excludeexcludeexclude`.
- Let's say that we have a `src` folder with several files in it, and I want to compile all the files except one called `index.ts`.

- Only to compile `index.ts` successfully.

> [TypeScript - files](https://www.typescriptlang.org/tsconfig#files)
> [TypeScript - include](https://www.typescriptlang.org/tsconfig#include)
> [TypeScript - exclude](https://www.typescriptlang.org/tsconfig#exclude)
### Out put compiled files into another folder.
When we compile ts files, it will generate js files within the same folder, but most of the time we will need to separate them, usually there will be a `dist` folder as files like `html`, `css` or `js` files will be here.
We can go to `tsconfig.json` file and locate `outdir` and uncomment it, then we can specify which folder should receive compiled files.

Here I specify that the folder called `dist`, and run `tsc`.

A new folder called `dist` has been generated with the files that compile from `src` folder.

### Target setting
We might choose to set a lower target if your code is deployed to older environments, or a higher target if your code is guaranteed to run in newer environments.

> [TypeScript - Target](https://www.typescriptlang.org/tsconfig#target)