Why make illegal states impossible to represent?
Tags: react, typescript, rescript, typesystem
Published: 2021-02-27 20:06:04

---
title: Why make illegal states impossible to represent?
published: true
description: Create React Components which could not have invalid states.
tags: React, TypeScript, ReScript, TypeSystem
//cover_image: https://direct_url_to_image.jpg
---
 > This is a continuation to [https://dev.to/acsreedharreddy/when-could-should-we-merge-two-states-3e60](https://dev.to/acsreedharreddy/when-could-should-we-merge-two-states-3e60)

**React Component** is a function that takes in props, state and returns the view for that particular state and props.
```
f(props,state) => view
```
So our component has to handle all the possible types of props and states.

#### Let us create a Post component:
```jsx
function Post({ id }) {
  const [{ loading, error, data }, dispatch] = useReducer(reducer, {
    loading: true,
    error: null,
    data: null,
  });
  useEffect(/* Load the data */);

  return (
    <div>
      {loading && <Loading />}
      {error && <Error />}
      {data && <Body data={data} />}
    </div>
  );
}
```
>We wanted the component to either render `Loading` or `Error` or `Body` component.

But the issue with this component is:
 * The Component would render both **the `Loading` component and  `Data` component** when the state is `{loading: true, data: "...", error: null}`.

# Why does this happen?

The total number of **possible states** for the above component are
>2(loading true | false) * 2(data | null) * 2(error | null) = **8 states**

Of these 8 states only three are valid states
1. `{loading: true, data: null, error: null}` when the data is **loading**.
2. `{loading: false, data:{...}, error: null}` when the data is **loaded**.
3. `{loading: false, data: null, error: {...}}` when there is an **error**.

> When the state is anything other than the above three, our component renders an inconsistent View.

I could think of two ways to prevent invalid states:
1. **Write code more carefully** so that we would never have inconsistent states. But we would **not be 100% sure**.
2. **Make illegal states impossible to represent** so that this type of state `{loading: true, data: {...}, error: null }` is impossible to create.


# How can we Make illegal states impossible to represent?
We can achieve this with the help of *Sum Type* in a type system. 

```ts
type state = 
    |{type:"Loading"} 
    |{type:"Error",error:string}
    |{type:"Data",data:string}
```
It is called as an Union(TypeScript), Variant(ReScript).

So now the state could be one of the above three types. Then the total number of possible types of states come down to
> 1(Loading) + 1(Error) + 1(Data) = **3 states**.

Since we have made illegal states impossible to represent, **State will always be a valid one** and we just have to **create a React component which deals with three types of states**.

The component becomes
```tsx
type state = 
    |{type:"Loading"} 
    |{type:"Error",error:string}
    |{type:"Data",data:string}

function Post({ id }) {
  const [state, dispatch] = useReducer(reducer, {
    type: "Loading",
  });
  useEffect(/* Load the data */);

  switch (state.type) {
    case "Loading":
      return <Loading />;
    case "Error":
      return <Error />;
    case "Data":
      return <Data data={state.data} />;
  }
}
```
> Here we reduced the possible states from 8 to 3. But in our real-world scenarios, the numbers would be much larger than these and by reducing the possible states we reduce the complexity of the component.