Repository: tannerlinsley/react-query (ts)

Issue:
React Query Devtools cannot serialize BigInt type
**Describe the bug**
One of the models that I am caching with React Query is a BigInt type. Unfortunately, when I try and inspect the data in the devtools explorer, I get an uncaught error: `TypeError: Do not know how to serialize a BigInt`.

**To Reproduce**
Steps to reproduce the behavior:
1. Add an object using a BigInt type to the query cache
2. Open the Devtools
3. Select the query in the browser to inspect the data
4. See the error

**Expected behavior**
I should be able to view properly serialised data in the devtools browser.

**Screenshots**
![image](https://user-images.githubusercontent.com/48416253/145600948-09d8ea8f-a75b-4b1a-a382-73d54bd62942.png)

**Desktop (please complete the following information):**
 - OS: Pop_OS 21.04
 - Browser: Chrome
 - Version: 94

**Additional context**
The error can be traced to this line: https://github.com/tannerlinsley/react-query/blob/master/src/devtools/Explorer.tsx#L112. If there's a reason that the data is being stringified, then hopefully there's a way to keep doing it, but there are data types which cannot be parsed by JSON.stringify. There may be other options, such as https://github.com/blitz-js/superjson but I understand that would add further complexity.


Pull request description:
fix(devtools): serialize bigint types
closes #3082 

### Detail
I detected the issue `TypeError: Do not know how to serialize a BigInt` was caused by `JSON.stringify` in the devtools explorer. I created a separate function so I could also write a test. 

This is my first contribution here, so please, let me know how I can improve this implementation. 😄


Patch:
diff --git a/src/devtools/Explorer.tsx b/src/devtools/Explorer.tsx
index 7c97ae6f9..fe4474590 100644
--- a/src/devtools/Explorer.tsx
+++ b/src/devtools/Explorer.tsx
@@ -1,6 +1,6 @@
 import React from 'react'
 
-import { styled } from './utils'
+import { displayValue, styled } from './utils'
 
 export const Entry = styled('div', {
   fontFamily: 'Menlo, monospace',
@@ -154,10 +154,7 @@ export const DefaultRenderer: Renderer = ({
         </>
       ) : (
         <>
-          <Label>{label}:</Label>{' '}
-          <Value>
-            {JSON.stringify(value, Object.getOwnPropertyNames(Object(value)))}
-          </Value>
+          <Label>{label}:</Label> <Value>{displayValue(value)}</Value>
         </>
       )}
     </Entry>
diff --git a/src/devtools/utils.ts b/src/devtools/utils.ts
index eabac204c..1c8bfa750 100644
--- a/src/devtools/utils.ts
+++ b/src/devtools/utils.ts
@@ -123,6 +123,17 @@ export function useSafeState<T>(initialState: T): [T, (value: T) => void] {
   return [state, safeSetState]
 }
 
+/**
+ * Displays a string regardless the type of the data
+ * @param {unknown} value Value to be stringified
+ */
+export const displayValue = (value: unknown) => {
+  const name = Object.getOwnPropertyNames(Object(value))
+  const newValue = typeof value === 'bigint' ? `${value.toString()}n` : value
+
+  return JSON.stringify(newValue, name)
+}
+
 /**
  * Schedules a microtask.
  * This can be useful to schedule state updates after rendering.


Test patch:
diff --git a/src/devtools/tests/Explorer.test.tsx b/src/devtools/tests/Explorer.test.tsx
index 7a14ad404..f4077f701 100644
--- a/src/devtools/tests/Explorer.test.tsx
+++ b/src/devtools/tests/Explorer.test.tsx
@@ -2,6 +2,7 @@ import React from 'react'
 import { fireEvent, render, screen } from '@testing-library/react'
 
 import { chunkArray, DefaultRenderer } from '../Explorer'
+import { displayValue } from '../utils'
 
 describe('Explorer', () => {
   describe('chunkArray', () => {
@@ -54,4 +55,14 @@ describe('Explorer', () => {
       expect(toggleExpanded).toHaveBeenCalledTimes(1)
     })
   })
+
+  describe('displayValue', () => {
+    it('when the value is a boolean', () => {
+      expect(displayValue(true)).toBe('true')
+    })
+
+    it('when the value is a BigInt', () => {
+      expect(displayValue(BigInt(1))).toBe('"1n"')
+    })
+  })
 })