Typescript Fundamentals Part 2:
Tags: typescript, javascript, programming, webdev
Published: 2023-03-03 13:40:40

In part 1 of this article - read [here](https://dev.to/jamesoyanna/typescript-fundamentals-part-1-12ep),  we took a look at the fundamental concepts of Typescript, including its syntax, data types, and functions.

Now let's look at some conceptual aspects of types and type systems.

### Union and Intersection Types
Union and intersection types can conceptually be thought of as logical boolean operators (AND, OR) as they pertain to types
Union Type is a type that can have multiple possible types. It is denoted using the | symbol.
 
Let's take a look at an example. Consider this piece of code below

![Union-types](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnvjs74wsednsrkttzev.PNG)


The type Address above can be either a string or a number. When we try to set Adddress to true, we get an error of 

`Error: Type 'boolean' is not assignable to type 'string | number'`.

Let’s write a function that can operate on strings or numbers as well:

![Print-id](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wg5940cojghny576iabq.PNG)

If we try to execute the function `printId` by passing a number or a string as an argument, this will work fine. 

`printId(101); // work fine
printId("202"); // work fine
printId(true); // throws an error
`

We are going to get an error if we pass any other type other than a string or a number.

![ts-error](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3nvj2jsii2dqycznmk8p.PNG)

### Intersection type:
An intersection type is a type that combines two or more types into a single type. It is denoted using the & symbol. 
Let's look at an example:

![Type-insection](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zhqsmk888rp37661kg5t.PNG)

In the example above, the person type is an intersection of `name and age`, which means that any value of type `person` must have all the properties of name and age.

The `james` variable is of type `person` and has all the required properties, so it is allowed. However, the `kola` variable does not.

### Interfaces and Type Aliases
Typescript provides two mechanisms for centrally defining types and giving them useful and meaningful names: interfaces and type aliases. 

We will study both concepts in depth, and explain when it makes sense to use each type. 
Interfaces and type aliases are both used to define custom types that can be used throughout our codebase. 

### Type aliases:
Consider this piece of code: `{name: string, email: string}`. It's a syntax we’ve used before for type annotations. 

This syntax will get increasingly complicated as more properties are added to this type. 

Furthermore, if we pass objects of this type around through various functions and variables, we will end up with a lot of types that need to be manually updated whenever we need to make any changes!

Type aliases help to address this, by allowing us to:
- define a more meaningful name for this type
- declare the particulars of the type in a single place
- import and export this type from modules, the same as if it were an exported value.	

 It can be used to make complex types more readable or to define a type that is used in multiple places in the codebase. 
Let's take a look at this example code:

![Locatiion-type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yel5oalrpuvtyw6b230p.PNG)

In the code above, `LocationType` is a type alias that defines an object with a city property of type string and a `cityCode` property of type number. The `lagos` variable is of type `LocationType` and has all the required properties, so it is allowed.

Lets take a look at how we can use type aliases in functions;
Consider this type alias code syntax ;


![IUser-info](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fnsfj756szq1szkgqyke.PNG)

Now consider this function

```
function printContactInfo(info: UserContactInfo)
 { console.log(info) console.log(info.email) 
} 
const painter = { 
name: "kola ojo", 
email: "kole@gmail.com", 
favoriteColor: "Off White", 
} 
printContactInfo(painter)
```

This code defines a function called `printContactInfo` that takes an argument of type `UserContactInfo `and prints it to the console. 

Also, we define an object called painter that has a name, email, and `favoriteColor` property.

Here, the` UserContactInfo` type is a type alias that is defined at the top.
 
`UserContactInfo` type defines an object that has a name and email property, which is why the painter object is able to be passed as an argument to the `printContactInfo` function.

When the `printContactInfo` function is called with the painter object as an argument, it logs the entire object to the console using console.log(info) and logs the email property using console.log(info.email). 

Since the painter object has an email property, both of these log statements will output the expected value to the console.

This example code demonstrates how type aliases can be used to define custom types in Typescript and how they can be used to create more expressive and type-safe code. 

By defining a` UserContactInfo` type alias, the code can ensure that any object passed to the `printContactInfo` function has the required properties, which helps to catch errors early in the development process.

### Interfaces
An interface is a Typescript feature that allows you to define the shape of an object, including its properties and methods.
Let's take a look at an example:


![types-interfaces](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u7obf0ft9v1fjtscc1ps.PNG)

Here in the code above, `Person` is an interface that defines an object with a name property of type string and an age property of type number.

The `james` variable is of type Person and has all the required properties, so it this work fine.

Lets take a look at another example;
consider the code below:

```

interface Userinfo {
  name: string;
  email: string;
}
function printUserInfo(info:Userinfo){
  info.name
 
}
```

Here we define an interface called `UserInfo` with two properties: name and email, both of which are of type string.

We define a function, `printUserInfo` that takes an argument of type `UserInfo`, and it accesses the name property of that argument using the dot notation (info.name). 
This is just how we can access an interface property in Typescript.

### Inheritance in interfaces
The way JavaScript class  “inherits” behavior from a base class, is the same as what Typescript calls a heritage clause: extends

Let's take a  look at an example of how we can use inheritance with classes and interfaces in Typescript.

```
class Animal {
  eat(food: string) {
    console.log(`Eating ${food}`);
  }
}

class Dog extends Animal {
  bark() {
    return "Woof";
  }
}

const d = new Dog();
d.eat("bone"); // Provide an argument to the eat method
```
This code illustrates how classes can inherit properties and methods from other classes using the extends keyword.

In the code snippet, we have two classes: Animal and Dog.

    The Animal class defines an eat method, which takes a food parameter of type string. This eat method is responsible for logging a message to the console, indicating that the animal is eating the specified food.

    The Dog class extends the Animal class. This means that it inherits all the properties and methods of the Animal class, including the eat method. In addition to inheriting, the Dog class also introduces its own method called bark, which returns the string "Woof."

When we create a new instance of the Dog class and assign it to the variable d, this instance inherits all the properties and methods from the Animal class, including the eat method. However, the bark method is specific to the Dog class and is not available on the Animal class.

To demonstrate the code in action, we invoke the d.eat("bone") method. TypeScript recognizes that d is an instance of the Dog class, which extends Animal, and allows us to call the eat method on the d instance while providing the required food parameter, in this case, "bone."

Furthermore, if we call d.bark(), TypeScript recognizes that d is an instance of Dog, which has a bark method, and it returns the string "Woof."

### Interfaces and type Aliases, which  one to choose:
Interfaces and type aliases are both useful tools for defining custom types in Typescript. 
Interfaces are often used to define the shape of an object, while type aliases are used to create more readable or reusable types.
In many situations, either a type alias or an interface would be perfectly fine, 

however, If you need to define something other than an object type (e.g., use of the | union type operator), you must use a type alias
If you need to define a type to use with the implements heritage term, it’s best to use an interface
If you need to allow consumers of your types to augment them, you must use an interface.