Generics in React
Tags: typescript, react, generics, beginners
Published: 2023-12-10 18:36:53

## What are generics
Have you defined a function/method in any language? If so, you probably know that we are able to define its parameters/arguments that are passed where function is called.  
By this we call pass the whatever the value we want to pass to a function and we can decide it at spot.

But have you ever wondered what if we want to decide the type of some identifier at spot rather than defining it where we created our function. This is where Generics come. Generics are simply the passing of dynamic type to the function (or type/interface) which can be used inside a function.

It might seem a lot. Let's have it through the example:

Usually what we do is

```ts
const exmapleFunction = (data: string)=>{
    console.log(data)
}

exmapleFunction("Exmaple Function Called")

```
In the above function, we can only pass the data as type of string. But we want data type to be dynamic. Here is what we do to make it dynamic:

```ts
const exmapleFunction = <T>(data: T) => {
  console.log(data);
};

exmapleFunction<Record<string, string>>({ id: '1', value: 'This is data' });

```

Now we can pass the dynamic type where we am calling the function, similar to the argument passing.

## Generics in React

Now let's make a component that uses Generics:
```ts
import { useState } from 'react';

type Props<T> = {
  data: T;
};

const MyComponent = <T,>(props: Props<T>) => {
  const [dataState, setDataState] = useState<T>(props.data);

  return <div></div>;
};

const App = () => {
  <MyComponent<string> data={'Example'}></MyComponent>;
};

```

Now we have passed the dynamic type, generic where we am using the MyComponent.

## Moving Further
Now we have learned that how we can make and pass the generics to our component. 
But what if we want to use generics, but still restrict some type. We want to allow the generics that must satisfy some constraints. We can do it by using the `extends` keyword.
Here is how:
```ts
import { useState } from 'react';

type ExtendedDataType = {
    id: number
    value: string
}

type Props<T extends ExtendedDataType> = {
  data: T;
};

const MyComponent = <T extends ExtendedDataType,>(props: Props<T>) => {
  const [dataState, setDataState] = useState<T>(props.data);

  return <div></div>;
};

const App = () => {
  <MyComponent<string> data={'Example'}></MyComponent>;
};

```

Now we defined a generic that must extends our `ExtendedDataType`, i.e the type we pass must have id as string and value as number in it. Hence the part of the code below shows the error, as string does not satisfy the constraint.

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ie4hf6tmqip6jrlcb4q.png)

Let's pas the correct now:
```ts
import { useState } from 'react';

type ExtendedDataType = {
  id: number;
  value: string;
};

type Props<T extends ExtendedDataType> = {
  data: T;
};

const MyComponent = <T extends ExtendedDataType>(props: Props<T>) => {
  const [dataState, setDataState] = useState<T>(props.data);

  return <div></div>;
};

type AppDataType = {
  id: number;
  value: string;
  key: string;
};

const App = () => {
  <MyComponent<AppDataType> data={'Example'}></MyComponent>;
};
```

Tada! Now we have correct type that is passed as generic. But notice we didn't change the value of data. That is why we are having this error:

![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ktb9y3af74c4naceudce.png)

Now we have to pass the data as type of `AppDataType`.
Here it is:
```ts
import { useState } from 'react';

type ExtendedDataType = {
  id: number;
  value: string;
};

type Props<T extends ExtendedDataType> = {
  data: T;
};

const MyComponent = <T extends ExtendedDataType>(props: Props<T>) => {
  const [dataState, setDataState] = useState<T>(props.data);

  return <div></div>;
};

type AppDataType = {
  id: number;
  value: string;
  key: string;
};

const appData = {
    id: 3,
    value: "appData",
    key: 'app-data-3'
}

const App = () => {
  <MyComponent<AppDataType> data={appData}></MyComponent>;
};
```

Now we have everything as we needed.
But what if we want to have some default value for generics, so if generics is not passed, that default value is considered. We can simply do that by:
```ts
const MyComponent = <T extends ExtendedDataType = ExtendedDataType>(props: Props<T>) => {
  const [dataState, setDataState] = useState<T>(props.data);

  return <div></div>;
};
```

Now even if we do not pass generics, we will have the `T` as `ExtendedDataType`:
```ts
const App = () => {
  <MyComponent data={{id: 3, value: 'value-3'}}></MyComponent>;
};

```
Note that we have not passed the generics, so T would be ExtendedDataType and so data would be of type ExtendedDataType, and hence we cannot pass data as `appData` because appData has one extra feature `key`, which ExtendedDataType lacks. 

That's it for today.
Hope it help you learned something.
Happy learning.