Let's talk about Typescript
Tags: javascript, typescript, programming, webdev
Published: 2022-08-15 13:04:00

JavaScript is now one of the most used programming languages today thanks to not only its flexibility, but also as a result of the internet boom. 


We access the internet using web browsers and JavaScript comes packaged with your web browser. At some point you're going to interact with JavaScript either as an end-user or a developer whether it's on your smartphone, or your smart TV, basically anything that will at some point talk to the internet.



## The "WHY" behind Typescript

![Question mark image](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/urhsd0pmmn7iljbqwjd6.jpg)

JavaScript isn't perfect though, in fact, it can get pretty frustrating to work with. JavaScript is a *dynamically typed language*. This means JavaScript will try to help you out even when you haven't asked it to.

Let's look at an example:


```js

let numberOne = 1;
let stringOne = "One"
let sum = numberOne + stringOne;
console.log(sum)
// Output
// 1One

```


Intuition will tell you that this operation should not be possible. How can we add a number to a string? JavaScript will take a look at it and say *"Hey human, I can help you with that"*, then proceed to change your number value into a string. 

While there are some benefits to this kind of behavior, it more often than not causes more harm than good. JavaScript will not complain about this behavior, until it absolutely has to.  

As a JavaScript developer, you've probably encountered this behavior before. For example passing in the wrong data type as a parameter to a function.


```js

const squareMe = (number) =>{
  return number * number;
}

// Let's call the function but pass in a string instead of a number
console.log(squareMe("five"))

// Output
// NaN

```

 
>:wave: *The most common kinds of errors programmers write are type errors, where the wrong type of value was used.*


Wouldn't it be nice if we could accurately determine how our code would execute without having to worry about Javascript playing judge, jury and executioner.


### Typescript to the rescue


![Superman Walking](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0iwrje95gqumnmll55t3.jpg)


Up to this point, we've been writing dynamic code. This is referred to as *dynamic typing*, where the language can decide to fill in the gaps when it needs to.
Typescript offers us a way out. Rather a way to limit the dynamic nature of JavaScript by allowing us to use *static typing* instead.


Static typing in a nutshell, is the opposite of dynamic typing. Instead of being as vague as possible when writing our code, we try to be as _*explicit*_ as possible. Let's declare a pair of variables using typescript.


```ts
 
 let numberOne:string = "One";
 let numberTwo:number = 2;  

```


This is what typescript allows us to do. We are explicitly declaring the data types our variables can hold. If we try to re-assign the variables with values that don't match the data types specified, typescript will complain.


```ts

numberOne = 1; // Error: type "string" is not assignable to number
numberTwo ="2"; // Error: type "number" is not assignable to string

```


You'll get immediate feedback from typescript write in your code editor. This `type checking` functionality is what has propelled typescript to be one of the most loved languages in recent years.

The [graph](https://survey.stackoverflow.co/2022/#section-most-loved-dreaded-and-wanted-programming-scripting-and-markup-languages) below is Stack Overflows' Annual Developer Report 2022 for the most loved programming languages.

![Stack overflow Annual developer report 2022](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/p450fsi6di01glgpg72z.png)

So Typescript in a nutshell, is still JavaScript, **but a statically typed or strongly typed JavaScript**.   

Now let's begin to look at some of the features that are available to us when using typescript starting with the `tsc`.


## The `tsc`


**TSC** stands for *typescript compiler*. The typescript compiler is the brains behind typescript. It gives us a plethora of options to choose from when it comes to configuration options.


Before we can even interact with typescript though, we need to first install it on our machines.


`npm i typescript -g`

or 

`yarn add typescript`


Confirm you have it installed by running `tsc -v` on your terminal.

```bash

tsc -v 
Version 4.7.4

```


To initialize a typescript config file, run the following command in your terminal window

`tsc --init`


This will generate a configuration file for you that the typescript compiler will then use to run your typescript code.


### Common Configuration options
They're a lot of options to choose from, but we won't dive into the details of what they all mean. We will however look at the common configuration options that you will more often than not be interacting with.


#### `noImplicitAny`
This configuration option ensures that types are not inferred. This has the added advantage of ensuring that we always pass in the correct types when executing our program. By default, tsc will infer the `any` type to your variables. This is the same behaviour vanilla javascript gives you.
With the `implicitAny` option enabled, variables inferred with the any type will issue an error.


#### `strictNullChecks`
This option allows us to handle operations that return `null` or `undefined` more elegantly. We've all at one point or the other forgotten that a particular function doesn't return anything and tried to operate on them.


####`target`
This option refers to the version that typescript will emit after transpiling your code to vanilla javascript. Remember your browser doesn't understand Typescript and that's why we need to specify the target version of javascript.


####`module`
Specify the JS Module System that you'd like to use.E.g `commonJS`, `AMD`, `ECMAScript`


####`strict`
The strict option specifies how strict tsc should be when it comes to type checking. As good practice, you should always have this option turned on.


## The basics
The `tsc` is responsible for checking your code before executing.  Let's look at an example of valid JavaScript code, that shouldn't intuitively work, but does.

```js
function shineMyName(firstName){
   console.log(`This little ${firstName} of mine, I'm gonna let it shine..`)
}
console.log(shineMyName())
// Output
// This little undefined of mine, I'm gonna let it shine.
```

That doesn't look right does it? We forgot to pass in the `firstName` parameter to our function, but we were still able to run our code. 


If you try to run the same code in typescript, you'll get immediate feedback from the `tsc` complaining that you didn't pass in all the parameters. 

```ts

 function shineMyName(firstName){
   console.log(`This little ${firstName} of mine, I'm gonna let it shine..`)
}
console.log(shineMyName())
// Expected 1 argument  but got 0 ts(2554)
// An argument for firstName was not provided

```

Let's add more type-checking capabilities by explicitly defining the data types.


```ts

function shineMyName(firstName:string){
   console.log(`This little ${firstName} of mine, I'm gonna let it shine..`)
}
console.log(shineMyName("Bob"))

```
This is referred to as *type annotating*. Let's look at a few more example of type annotation.
```ts

let lastName: string = "Marley";
let age:number = 45;

```
This method of annotating is called *explicit typing* where we explicitly define the type of value. 

Typescript also has the ability to infer types. This is called _type inference_

```ts
let lastName = "Marley"; // string 
let age = 45; // Number
```

> :bulb: When you don't explicitly annotate the types, typescript will infer the types for you. This is called _implicit annotating_.

### Primitive types in Typescript 
- _String_
- _number_
- _boolean_
- _null_
- _undefined_
- _void_
- _never_
- _any_
- _symbol_
- _bigint_

```ts
let firstName: string = "Mark";
let age:number = 30;
let isCool:boolean = true;
let bigNum:bigint = 100n;
let weDintKnow:any = "I don't know";
let maybeWeknow:unknown = "I might know";
let notDefined:undefined = undefined;
let nulling:null = null;
let never:never;
let symbol:symbol = Symbol("symbol");
let voided:void = undefined;
```

#### Defining Types in Typescript

##### Arrays
To specify an array in typescript, we use the syntax `type[]`. You start by defining the data types that the array will include followed by a pair of square brackets.

```ts

let lyrics: string[] = ["Hey", "I", "Just", "Met", "you", "and", "this","is","crazy","but","here's","number","so","call","me","maybe"]

```
We first define the types of values that should be stored in our array. In our example, we can only have strings in our array.

##### Tuples
A tuple resembles an array but with a few differences:
- The length of the tuple is fixed,
- The tuple can have a mix of data types,

```ts

let rgb:[number,number,number] = [239,120,200]

```


##### Functions
You'll want to check the type of values being passed to our functions and define the type of value that the function should return. 
We can do this by annotating our arguments as well as defining the type of value to be returned.


```ts

  function lyricsMatch(lyrics:string[]):string{
    return lyrics.join(' ');
  }

console.log(lyricsMatch(["Hey", "I", "Just", "met", "you","," "and", "this","is","crazy","but","here's","number","so","call","me","maybe"]))

// Hey I just met you, and this is crazy but here's my number, so call me maybe
```

We're explicitly telling typescript, that our function will take a single argument that has to be an array of string(s). We are also indicating that our return value will be a string as well.

If we try to pass in a parameter that isn't an array of string(s), the tsc will complain.

```ts

lyricsMatch("I'm never gonna dance again")
// Argument of type string is not assignable to string[]

```



##### Union Types
A `union` type is a combination of one or more  types. Let's look at an example.

```ts
 
 function returnAge(age:string|number){
  return age;
}

console.log(returnAge(20))
console.log(returnAge("20"))
// The age argument can either be number or string type
// Both calls to `returnAge` will execute successfully.

```

Something to keep in mind though is that when you use unions, you can't use methods that are available to one of the data types only. 

For example we can't do something like `age.toUpperCase()`.
If the parameter that we passed in was a number, it wouldn't work. To get around this, we use *narrowing*. 

```ts

 function returnAge(age:string|number){
  if(typeof age === "string"){
    return age.toUpperCase()
  }
  return age;
}

```

*Narrowing* simply means we try to deduce the data type that was passed in. If it's of type string, then we know we can use the `toUpperCase()` method on it. 

##### Type aliases

Let's define an object shape


```ts

{
  name:string,
  material:string,
  status?:boolean
}

```

Now let's assume we want to keep reusing this shape throughout our code base. We can save this blueprint using *type aliases*.

```ts
 type glassJar = {
  name:string,
  material:string,
  status?:boolean
 }
```

![Glass Jar](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yzvlvjqfk6vvvbcmxmch.jpg)

Now we can reuse this object shape anywhere in our code base without having to keep rewriting the shape itself. 

```ts
const jarOne: glassJar = {
  name:"Mikes Jar",
  material:"glass",
}
```

You can use type aliases to define any type of data structure and not just objects.

```js
type ID = number | string;
type userIDs = string[] | number[];
```



##### Interfaces

An *interface* is an alternative syntax that we can use to create objects.


```js
interface glassJar:{
  name:string,
  material:string,
  status?:boolean
 }

const jarOne: glassJar = {
  name:"Mikes Jar",
  material:"glass",
}
``` 

#### Literal Types

To explain type literals, we need to think about `let`,`var` and `const` and how typescript interprets these values. 

We know that using `let` and `var` allows us to change the values at a later time.

```ts
 let buzz = "Buzz Light Year";
 var woody = "woody";

 // How typescript represents this: let woody:string
// let buzz:string`
```
We are telling the compiler that we want the values represented by the two variables to be any string values. 

But what about declaring types with `const`. These are values that we don't plan on ever-changing.


```ts
const peterParker = "Spidey";

// How typescript represents this:
// const peterParker:"spidey"
```

Because we can only represent a single string value, the variable is assigned the type "spidey".


##### Conclusion
:bulb:_The biggest advantage of using typescript is the ability to catch type related bugs at compile time_.  
I only scratched the surface in terms of what typescript can do but hopefully this post can push you to adopt it if you haven't already. It's a great tool that will boost the quality of the code that you write. 

Thanks for reading and happy coding. :wave: