Typescript Generics Quick Intro with react basics
Tags: react, typescript, generics, javascript
Published: 2019-10-08 17:58:39

In this article, we're going to look over how **Generics** work in **Typescript**. Literally, it looks scary at the beginning but when we understand and breaks the overall logic of generics in chunks then they will become our best friends.
> This article needs some basic understanding of typescript to advance further.

###Array in typescript
Most basic type of generics we always use is defining array of particular type. For instance:number[],string[],boolean[];
```javascript
type numArr = Array<number>;
type strArr = Array<string>;
type boolArr = Array<boolean>;

let numberArray: numArr = [1, 2, 3, 4];
let stringArray: strArr = ["H", "e", "l", "l", "o"];
let boolArray: boolArr = [true, false, true];

console.log(numberArray);
console.log(stringArray);
console.log(boolArray);
```
If we not pass any particular type then it will show error on screen like below pic.

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/ve622weqa4hk09barspv.png)

###Generic Methods
Suppose we need a method which can return middleElement of any array type passed to it. So most basic approach to find middleElement will be like this :
```javascript
const middleElement = (arr: Array<any>) => {
  return arr[Math.floor(arr.length / 2)];
};

let numberArray: numArr = [1, 2, 3, 4, 5];

let stringArray: strArr = ["I", "T", "A", "L", "Y"];

let boolArray: boolArr = [true, false, true];

let middle1 = middleElement(numberArray);

let middle2 = middleElement(stringArray);

let middle3 = middleElement(boolArray);

console.log(middle1); //3
console.log(middle2); //A
console.log(middle3); //false
```
But in this way, we will loose the **TypeDefinition** of the return type of method as you can see in below pic which shows 'any' when we hover over it.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/a7via0tttt93rym25ino.png)

Now if we implement generics feature of typescript then we can retain the typeDefinition of the method.

```javascript
const middleElement = <T>(arr: Array<T>) => {
  return arr[Math.floor(arr.length / 2)];
};
```

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/gzasqcwrxiqpei1yflm6.png)

We can see in above pic, when we hover over any middleElement method of certain type, we see its argument passed type & its return type.

```javascript
//We can explicitly define type of our method as below :
let middle2 = middleElement<string>(stringArray);
```

######To make a method which can accept more than one generic type we can do the following :
```javascript
//This method will accept any type of arguments and make a combined object of it.
const makeObj = <X, Y>(x: X, y: Y) => {
  return { x, y };
};

let numbArray: numArr = [1, 2, 3, 4];

let Obj = { firstName: "Vinod", lastName: "Chauhan" };

let newObj = makeObj(numbArray, Obj);

console.log(newObj);
```
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/0he2wg2juxdfzj5axead.png)

We can see the return type of makeObj method in above pic, this shows the power of generics with VS Code editor.


####Generic Method with required fields
Let say we need a method 'makeICardDetail' which takes an object as a parameter. This object required firstname,LastName,age as a mandatory fields to fullfill its requirement. So one way of doing this will be :
```javascript
const makeICardDetail = (obj: {
  firstName: string;
  lastName: string;
  age: number;
}) => {
  return {
    ...obj, //Copy other contents of Object as it is.
    ICard: obj.firstName + " " + obj.lastName + ", " + obj.age
  };
};

let makeNewDetail = makeICardDetail({
    firstName: "Vinod",
    lastName: "Chauhan",
    age: 27
  });
console.log(makeNewDetail.ICard); //Vinod Chauhan, 27
```
Now, What if I need to pass location also but not as a mandatory field. If I pass location field in makeICardDetail as a argument, typescript compiler gives me error on it.
```javascript
let makeNewDetail = makeICardDetail({
  firstName: "Vinod",
  lastName: "Chauhan",
  age: 27,
  location: "India"
});
console.log(makeNewDetail.ICard); //Vinod Chauhan, 27

//TSC compiler
index.ts:59:3 - error TS2345: Argument of type '{ firstName: string; lastName: string; age: number; location: string; }' is not assignable to parameter
of type '{ firstName: string; lastName: string; age: number; }'.
  Object literal may only specify known properties, and 'location' does not
exist in type '{ firstName: string; lastName: string; age: number; }'.

59   location: "India"
     ~~~~~~~~~~~~~~~~~

[9:01:00 PM] Found 1 error. Watching for file changes.
```

Here Generics come to rescue us with its 'extends' feature.
```javascript
const makeICardDetail = <T extends { firstName: string; lastName: string; age: number }>( obj: T) => {
  return {
    ...obj,
    ICard: obj.firstName + " " + obj.lastName + ", " + obj.age
  };
};
```
And if you look at below pic, you can see 'makeNewDetail' variable gives option of all possible values in it which help us in complex and lengthy application.
![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/c6goqmqf3minmmyzubrm.png)

###Interface with Generics
```javascript
interface KeyPair<T, U> {
  key: T;
  value: U;
}

let kv1: KeyPair<number, string> = { key: 1, value: "Vinod" }; // OK
let kv2: KeyPair<number, number> = { key: 2, value: 12345 }; // OK
```

### Generics in React 
If you have ever worked on React with typescript, you must have implemented functional components where 'props' has to be passed. props provide typedefinition to components.
```javascript
import React from "react";

interface Props {
  name: string;
}

export const Example: React.FC<Props> = ({ name }) => {
  return <div>Hello {name}</div>;
};
```
In above snippet, "React.FC<Props>" props are passed as generic to it which is type of interface where fields have there type declared with them.

Also we can define generics with useState.
```javascript
export const Example: React.FC<Props> = ({name}) => {
//const [state] = React.useState({fullName:"",age:0});
    const [state] = React.useState<{fullName:string | null;age : number}>({fullName : "",age:0});
  return <div>Hello {name}</div>;
};
```

I hope this article will add a small amount of knowledge in your react learning with typescript.