Functional JavaScript in 3 minutes: Is this function pure? Quick checklist ✅
Published: 2024-02-08 17:50:08



Remember functions from math class? 

![function graph](https://f005.backblazeb2.com/file/catreview/function.png)

For every **x**, there is a corresponding **y**.

FP paradigm is based on this idea of treating functions as mathematical functions.

Functions should:

- consistently produces the same output for a given input
- does not cause observable side effects.

*Everything that is not a function is a procedure.*

Programming is not math. But certainly, we can take advantage of math in programming. There are many benefits of doing so, such as:

- Easier to reason about
- Easier to test
- Easier to debug

The whys are a separate discussion. But for now, let's focus on what the headline of this article promised - the pure functions.

### Pure Function

#### Always has output, for *every* input.


Check out the code below: What if the input is null or undefined? Or it's anything other than 'sunny,' 'rainy', or 'snowy'? 

```js
❌

function getWeatherIcon(weather) {
  if (weather === 'sunny') {
    return '🌞';
  } else if (weather === 'rainy') {
    return '🌧';
  } else if (weather === 'snowy') {
    return '⛄';
  }
}
```

Below, we added a fallback. Now, we have an output for every input.

```js
✅

function getWeatherIcon(weather) {
  if (weather === 'sunny') {
    return '🌞';
  } else if (weather === 'rainy') {
    return '🌧';
  } else if (weather === 'snowy') {
    return '⛄';
  } else {
    return '🤷'; // fallback 
  }
}
```

What about narrowing the range with TypeScript?

```typescript
function getWeatherIcon(weather: 'sunny' | 'rainy' | 'snowy') {
  if (weather === 'sunny') {
    return '🌞';
  } else if (weather === 'rainy') {
    return '🌧';
  } else if (weather === 'snowy') {
    return '⛄';
  }
}
```

This function is pure - you are not allowed to pass anything other than 'sunny', 'rainy' or 'snowy' ✅ 

Of course, technically speaking, TypeScript is just a linter, and we are all going to hell for doing FP in JS, but this solution is good enough. This is a *contract* for developers, making it clear what the function can accept and what it returns.


#### The output is always the same for the same input.

Pure function - same input, same output:

```javascript
✅

function add(a, b) {  
  return a + b;
}
```

Impure function - same input, different output:

```js
❌

function getRandomEmojii(emojis) { 
  return emojis[Math.floor(Math.random() * emojis.length)];
}

getRandomEmojii(['🌞', '🌧', '⛄']);

```




#### No side effects

<Aside>
What is a side effect? Any change in the system that is observable to the outside world, such as:
</Aside>

- Modifying shared state (such as global variables, variables in parent functions scope)

```js
❌

let post = {
  title: 'Pure functions are awesome!',
  comments: [],
};

function addComment() {
  post.comments.push('Great post!');
}

addComment(post);
```

`addComment(post)` is impure call - it modifies the outside world - global variable `post` 


```js
❌

function addComment(post, comment) {
  post.comments.push(comment);
}

addComment(post);
```

Still impure - `comments.push()` modifies the input object 



What can we do about it?

```typescript
✅

function addComment({post, comment}: CommentDTO) {
  return {
    ...post,
    comments: [...post.comments, comment],
  } 
}
```

Now, we are not modifying the input, we create a new copy of an object with the new copy of comments array. ✅

- Making a network request:

```ts
❌

function createComment({title, body, author}: Comment) {
  return someAjax('https://api/comments', {
    method: 'POST',
    body: JSON.stringify({title, body, author})
  });
}

```

As side effects are not avoidable in real-world applications, the way we often deal with that is by isolating pure and impure parts of the code.
For instance, instead of calling `someAjax` directly, we could return a function that *will eventually* make a network request:

```js
✅

function createComment({title, body, author}: Comment) {
  return () => someAjax('https://api/comments', {
    method: 'POST',
    body: JSON.stringify({title, body, author})
  });
}

const createCommentRequest = createComment({
  title: '...', body: '...', author: '...'
});
// no side effects yet

```

By doing so, we can handle all side effects in one place, in a controlled way, and keep the rest of the code pure. ✅

Those were *some* examples of side effects, but there are many more. The point is, pure function should not alter, rely on, or interfere with anything outside of itself, in a way that is observable to the outside.

What it should do is **reliably produce the same output for the same input**, every time.


TLDR, is this function pure?

- Always has an output for *every* input. ✅
- The output is always the same for the same input. ✅
- Does not alter/rely on the outside world ✅