Spread syntax gotcha in JavaScript class methods
Tags: javascript, typescript, react, hooks
Published: 2019-03-31 00:28:13

---
title: Spread syntax gotcha in JavaScript class methods
published: true
tags: JavaScript,TypeScript,React,Hooks
canonical_url: https://www.slightedgecoder.com/2019/03/30/spread-syntax-gotcha-in-javascript-class-methods/
cover_image: https://thepracticaldev.s3.amazonaws.com/i/l19dkoi3biycx13q8tt2.jpg
---

_Photo by [Jay](https://unsplash.com/photos/dkFJST9zZZo?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/search/photos/pokeball?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) – Don’t get caught_

## _Watch out when exposing a mutable data structure with React Hooks_

When you spread an object instance of a class to expose methods, methods might not be copied over.

Suppose that you have a `Trie` class,   
which you want to make it immutable by returning a new object using syntax spread.

**_Not a good idea! Explained later._**

{% gist https://gist.github.com/dance2die/3107d7b0a3d3eeeb0dcad5886f5b1bf9 %}

Printing out `trie` object instance returned from `useTrie` won’t show `has` and an empty method is printed.

{% gist https://gist.github.com/dance2die/4192b1bab9e70e046515b456c147baf8 %}

Let’s see why and how to solve the issue.


## 🔬 Analysis

To understand the problem, let’s see how the class is [transpiled using TypeScript compiler](https://www.typescriptlang.org/play/index.html#src=class%20Trie%20%7B%0D%0A%20%20has(word)%20%7B%20return%20true%3B%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20Trie2%20%7B%0D%0A%20%20has%20%3D%20(word)%20%3D%3E%20true%3B%0D%0A%7D%0D%0A) (the transpiled babel code does the same but verbose so using TypeScript compiler here).

{% gist https://gist.github.com/dance2die/7419342babb86cafb72aaae443cff2c2 %}

`has` method was added to the prototype, not to an instance of `Trie` class.  
So `has` is still available when you do `const t = new Trie(); t.has(); // true`.

Returning a new object using spread syntax didn’t copy `has`   
because [spread syntax only copies own & enumerable properties](https://dmitripavlutin.com/object-rest-spread-properties-javascript/#12ownproperties).

But `prototype`[is not enumerable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype) so `has` is not copied over.

## 🧙‍♂️ Resolving the Issue

You can resolve the issue in two ways.

1. [Binding](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind)the method explicitly to `this`.
2. Using an [arrow function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions).

#### 1. Bind Explicitly

You can explicitly bind `this` to the method in the constructor.

{% gist https://gist.github.com/dance2die/0e123ece5776d334bf5e7fe39d88410b %}

, which is TypeScript-transpiled as

{% gist https://gist.github.com/dance2die/8e5597304ea3246396d1c40506169736 %}

And printing the `trie` instance returned from `useTrie` will now show `.has` method.

{% gist https://gist.github.com/dance2die/95b8a2bbf71316895673148e56441f18 %}

`has` is still added to the `prototype`, which might not be what you want and it’s increasing the file size.

So this brings us to,

#### 2. Using an arrow function expression

When you declare the `has` method using an arrow syntax, it’s transpiled by Transcript as shown below.

{% gist https://gist.github.com/dance2die/5c1a5a0252c3851fc22bb95f3da0b117 %}

You can see that it’s [same](https://gist.github.com/dance2die/8e5597304ea3246396d1c40506169736#file-transpiled-bound-trie-js) without `has` being assigned to the `prototype`.  
And the console log will still show `has` as part of the `trie` instance returned from `useTrieUsingArrow`.

{% gist https://gist.github.com/dance2die/0d5a69a187ab07e9234bad36dbe72cad %}

## 🤦‍♂️ Why? Why? Why?

I recently released a new package [@cshooks/usetrie](https://www.npmjs.com/package/@cshooks/usetrie) and [Nick Taylor](https://www.iamdeveloper.com/) 

{% user nickytonline %}

generously provided an educational & thorough PR on how the code-base can be improved.

But not having a deep knowledge of TypeScript & Javascript, the [following change](https://github.com/cshooks/hooks/pull/11#pullrequestreview-219222430) caused an issue.

{% gist https://gist.github.com/dance2die/13306ec6ab90419382e933434a131ad5 %}

FYI – `useTrie` is implemented as shown below.

{% gist https://gist.github.com/dance2die/043283084a0ae76b7a8bef2c86799fb6 %}

I was retro-fitting a mutable data structure and exposing it as a hook.

_But it’s not a good way as you can see between_ [_Paul Gray_](https://twitter.com/PaulGrizzay) _&_ [_Dan Abramov_](https://twitter.com/dan_abramov)_‘s tweets._

{% twitter 1105941010344038401 %}
{% twitter 1105946933955301377 %}


So be aware of the issue discussed above when you are extracting an imperative logic out of React.

## 🎉 Parting Words

I’ve paid handsomely for not following React way of doing things.   
I hope you the gotcha & the workaround helped you understand what’s going on behind the scenes.

You can play around with the TypeScript transpiler on the [Playground page](https://www.typescriptlang.org/play/index.html#src=class%20Trie%20%7B%0D%0A%20%20has(word)%20%7B%20return%20true%3B%20%7D%0D%0A%7D%0D%0A%0D%0Aclass%20Trie2%20%7B%0D%0A%20%20has%20%3D%20(word)%20%3D%3E%20true%3B%0D%0A%7D%0D%0A)
& the console log results in the [Sandbox](https://codesandbox.io/s/xjm96w0wmp).

_The post [Spread syntax gotcha in JavaScript class methods](https://www.slightedgecoder.com/2019/03/30/spread-syntax-gotcha-in-javascript-class-methods/) appeared first on [Sung's Technical Blog](https://www.slightedgecoder.com)._