From b7c28dc33bf928f6306379d9f800cf3336a03d62 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Tue, 8 Dec 2020 21:54:49 +0200
Subject: [PATCH 01/56] Added tsconfig.json. Modified eslint config

---
 .eslintrc                       | 13 +++++++++----
 jest.config.js                  |  1 +
 package.json                    |  2 ++
 test/autoCleanup.disabled.js    |  1 +
 test/autoCleanup.noAfterEach.js |  1 +
 tsconfig.json                   |  6 ++++++
 6 files changed, 20 insertions(+), 4 deletions(-)
 create mode 100644 tsconfig.json

diff --git a/.eslintrc b/.eslintrc
index d6c4554f..a7a4ea02 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,10 +1,15 @@
 {
-  "extends": "./node_modules/kcd-scripts/eslint.js",
+  "extends": [
+    "./node_modules/kcd-scripts/eslint.js",
+    "plugin:@typescript-eslint/recommended"
+  ],
   "rules": {
     "max-lines-per-function": "off",
     "no-constant-condition": "off",
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
-    "no-console": "off"
-  }
-}
+    "no-console": "off",
+    "no-use-before-define": "off",
+    "@typescript-eslint/no-use-before-define": "warn"
+  },
+}
\ No newline at end of file
diff --git a/jest.config.js b/jest.config.js
index c2e6a069..46c43d71 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,3 +1,4 @@
+// eslint-disable-next-line
 const { jest: jestConfig } = require('kcd-scripts/config')
 
 module.exports = Object.assign(jestConfig, {
diff --git a/package.json b/package.json
index cb1f5f57..24eb78b1 100644
--- a/package.json
+++ b/package.json
@@ -40,6 +40,8 @@
     "@types/testing-library__react-hooks": "^3.4.0"
   },
   "devDependencies": {
+    "@typescript-eslint/eslint-plugin": "^4.9.1",
+    "@typescript-eslint/parser": "^4.9.1",
     "all-contributors-cli": "6.19.0",
     "codecov": "3.8.1",
     "docz": "2.3.1",
diff --git a/test/autoCleanup.disabled.js b/test/autoCleanup.disabled.js
index d11f9314..174a3135 100644
--- a/test/autoCleanup.disabled.js
+++ b/test/autoCleanup.disabled.js
@@ -8,6 +8,7 @@ describe('skip auto cleanup (disabled) tests', () => {
 
   beforeAll(() => {
     process.env.RHTL_SKIP_AUTO_CLEANUP = 'true'
+    // eslint-disable-next-line
     renderHook = require('../src').renderHook
   })
 
diff --git a/test/autoCleanup.noAfterEach.js b/test/autoCleanup.noAfterEach.js
index 9b894e00..2531c657 100644
--- a/test/autoCleanup.noAfterEach.js
+++ b/test/autoCleanup.noAfterEach.js
@@ -9,6 +9,7 @@ describe('skip auto cleanup (no afterEach) tests', () => {
   beforeAll(() => {
     // eslint-disable-next-line no-global-assign
     afterEach = false
+    // eslint-disable-next-line
     renderHook = require('../').renderHook
   })
 
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..9fdd876b
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,6 @@
+{
+  "extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
+  "compilerOptions": {
+    "allowJs": true
+  }
+}

From a7b9412444e6aa8dab1fce7ca58b0160dc2c3ab0 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Thu, 10 Dec 2020 09:34:15 +1100
Subject: [PATCH 02/56] Convert src/cleanup.js to TypeScript

---
 src/{cleanup.js => cleanup.ts} | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)
 rename src/{cleanup.js => cleanup.ts} (62%)

diff --git a/src/cleanup.js b/src/cleanup.ts
similarity index 62%
rename from src/cleanup.js
rename to src/cleanup.ts
index d3172c46..ac8fe099 100644
--- a/src/cleanup.js
+++ b/src/cleanup.ts
@@ -1,4 +1,6 @@
-let cleanupCallbacks = []
+type CleanupCallback = () => Promise<void>
+
+let cleanupCallbacks: CleanupCallback[] = []
 
 async function cleanup() {
   for (const callback of cleanupCallbacks) {
@@ -7,12 +9,12 @@ async function cleanup() {
   cleanupCallbacks = []
 }
 
-function addCleanup(callback) {
+function addCleanup(callback: CleanupCallback) {
   cleanupCallbacks.unshift(callback)
   return () => removeCleanup(callback)
 }
 
-function removeCleanup(callback) {
+function removeCleanup(callback: CleanupCallback) {
   cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
 }
 

From cdfca10410405a8abfd06cb2ecfb21b76862c594 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Thu, 10 Dec 2020 09:41:21 +1100
Subject: [PATCH 03/56] Change src/cleanup.ts to use inline types

---
 src/cleanup.ts | 8 +++-----
 1 file changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/cleanup.ts b/src/cleanup.ts
index ac8fe099..7972347f 100644
--- a/src/cleanup.ts
+++ b/src/cleanup.ts
@@ -1,6 +1,4 @@
-type CleanupCallback = () => Promise<void>
-
-let cleanupCallbacks: CleanupCallback[] = []
+let cleanupCallbacks: (() => Promise<void>)[] = []
 
 async function cleanup() {
   for (const callback of cleanupCallbacks) {
@@ -9,12 +7,12 @@ async function cleanup() {
   cleanupCallbacks = []
 }
 
-function addCleanup(callback: CleanupCallback) {
+function addCleanup(callback: () => Promise<void>) {
   cleanupCallbacks.unshift(callback)
   return () => removeCleanup(callback)
 }
 
-function removeCleanup(callback: CleanupCallback) {
+function removeCleanup(callback: () => Promise<void>) {
   cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
 }
 

From 5e5a248ce1be4f05aa386707898dbd187b2cf784 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Thu, 10 Dec 2020 00:43:29 +0200
Subject: [PATCH 04/56] revert eslintrc

---
 .eslintrc | 13 ++++---------
 1 file changed, 4 insertions(+), 9 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index a7a4ea02..d6c4554f 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,15 +1,10 @@
 {
-  "extends": [
-    "./node_modules/kcd-scripts/eslint.js",
-    "plugin:@typescript-eslint/recommended"
-  ],
+  "extends": "./node_modules/kcd-scripts/eslint.js",
   "rules": {
     "max-lines-per-function": "off",
     "no-constant-condition": "off",
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
-    "no-console": "off",
-    "no-use-before-define": "off",
-    "@typescript-eslint/no-use-before-define": "warn"
-  },
-}
\ No newline at end of file
+    "no-console": "off"
+  }
+}

From 07278d0d64b919254fff812a47f93bac976d5901 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Thu, 10 Dec 2020 00:54:14 +0200
Subject: [PATCH 05/56] disable eslint for cleanup import

this can be reverted when `pure.js` is converted to typescript
---
 src/pure.js | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/pure.js b/src/pure.js
index 435d0736..c165fc19 100644
--- a/src/pure.js
+++ b/src/pure.js
@@ -1,6 +1,8 @@
 import React, { Suspense } from 'react'
 import { act, create } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
+// TODO: remove this line when it's converted to typescript
+// eslint-disable-next-line import/no-unresolved
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
 function TestHook({ callback, hookProps, onError, children }) {

From e8b9daedbe997acca58ed22ff12749be2697a941 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Thu, 10 Dec 2020 01:01:41 +0200
Subject: [PATCH 06/56] convert index to typescript
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

just a rename 😅
---
 src/{index.js => index.ts} | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 rename src/{index.js => index.ts} (100%)

diff --git a/src/index.js b/src/index.ts
similarity index 100%
rename from src/index.js
rename to src/index.ts

From bc2a6c334681ba6f6f44d53b951633a20f5646e2 Mon Sep 17 00:00:00 2001
From: Juhana Jauhiainen <juhana.jauhiainen@gmail.com>
Date: Thu, 10 Dec 2020 18:42:22 +0200
Subject: [PATCH 07/56] Worked on typing asyncUtils. Removed deprecated wait.
 Disabled import/no-unresolved for now

---
 .eslintrc                            |  3 +-
 src/{asyncUtils.js => asyncUtils.ts} | 66 ++++++++++-----------
 test/asyncHook.js                    | 88 ----------------------------
 3 files changed, 33 insertions(+), 124 deletions(-)
 rename src/{asyncUtils.js => asyncUtils.ts} (59%)

diff --git a/.eslintrc b/.eslintrc
index d6c4554f..a9ed07f2 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -5,6 +5,7 @@
     "no-constant-condition": "off",
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
-    "no-console": "off"
+    "no-console": "off",
+    "import/no-unresolved": "off"
   }
 }
diff --git a/src/asyncUtils.js b/src/asyncUtils.ts
similarity index 59%
rename from src/asyncUtils.js
rename to src/asyncUtils.ts
index afb5ac7e..864f38c5 100644
--- a/src/asyncUtils.js
+++ b/src/asyncUtils.ts
@@ -1,28 +1,37 @@
 import { act } from 'react-test-renderer'
 
-function createTimeoutError(utilName, { timeout }) {
-  const timeoutError = new Error(`Timed out in ${utilName} after ${timeout}ms.`)
-  timeoutError.timeout = true
+export interface WaitOptions {
+  interval?: number
+  timeout?: number
+  suppressErrors?: boolean
+}
+
+class TimeoutError extends Error {
+  timeout = true
+}
+
+function createTimeoutError(utilName: string, { timeout }: Pick<WaitOptions, 'timeout'>) {
+  //eslint-disable-next-line
+  const timeoutError = new TimeoutError(`Timed out in ${utilName} after ${timeout}ms.`)
   return timeoutError
 }
 
-function resolveAfter(ms) {
+function resolveAfter(ms: number) {
   return new Promise((resolve) => {
     setTimeout(resolve, ms)
   })
 }
 
-let hasWarnedDeprecatedWait = false
+// eslint-disable-next-line
+function asyncUtils(addResolver: any) {
+  let nextUpdatePromise: Promise<void | undefined> | null = null
 
-function asyncUtils(addResolver) {
-  let nextUpdatePromise = null
-
-  const waitForNextUpdate = async (options = {}) => {
+  const waitForNextUpdate = async (options: Pick<WaitOptions, 'timeout'> = {}) => {
     if (!nextUpdatePromise) {
       nextUpdatePromise = new Promise((resolve, reject) => {
-        let timeoutId
-        if (options.timeout > 0) {
-          timeoutId = setTimeout(
+        let timeoutId: number
+        if (options.timeout && options.timeout > 0) {
+          timeoutId = window.setTimeout(
             () => reject(createTimeoutError('waitForNextUpdate', options)),
             options.timeout
           )
@@ -33,17 +42,21 @@ function asyncUtils(addResolver) {
           resolve()
         })
       })
-      await act(() => nextUpdatePromise)
+      // eslint-disable-next-line
+      await act(() => nextUpdatePromise!)
     }
     await nextUpdatePromise
   }
 
-  const waitFor = async (callback, { interval, timeout, suppressErrors = true } = {}) => {
+  const waitFor = async (
+    callback: () => boolean | void | undefined,
+    { interval, timeout, suppressErrors = true }: WaitOptions = {}
+  ) => {
     // eslint-disable-next-line consistent-return
     const checkResult = () => {
       try {
         const callbackResult = callback()
-        return callbackResult || callbackResult === undefined
+        return callbackResult ?? callbackResult === undefined
       } catch (e) {
         if (!suppressErrors) {
           throw e
@@ -53,6 +66,7 @@ function asyncUtils(addResolver) {
 
     const waitForResult = async () => {
       const initialTimeout = timeout
+      // eslint-disable-next-line
       while (true) {
         const startTime = Date.now()
         try {
@@ -71,7 +85,7 @@ function asyncUtils(addResolver) {
           }
           throw e
         }
-        timeout -= Date.now() - startTime
+        if (timeout) timeout -= Date.now() - startTime
       }
     }
 
@@ -80,7 +94,7 @@ function asyncUtils(addResolver) {
     }
   }
 
-  const waitForValueToChange = async (selector, options = {}) => {
+  const waitForValueToChange = async (selector: () => unknown, options = {}) => {
     const initialValue = selector()
     try {
       await waitFor(() => selector() !== initialValue, {
@@ -95,25 +109,7 @@ function asyncUtils(addResolver) {
     }
   }
 
-  const wait = async (callback, { timeout, suppressErrors } = {}) => {
-    if (!hasWarnedDeprecatedWait) {
-      hasWarnedDeprecatedWait = true
-      console.warn(
-        '`wait` has been deprecated. Use `waitFor` instead: https://react-hooks-testing-library.com/reference/api#waitfor.'
-      )
-    }
-    try {
-      await waitFor(callback, { timeout, suppressErrors })
-    } catch (e) {
-      if (e.timeout) {
-        throw createTimeoutError('wait', { timeout })
-      }
-      throw e
-    }
-  }
-
   return {
-    wait,
     waitFor,
     waitForNextUpdate,
     waitForValueToChange
diff --git a/test/asyncHook.js b/test/asyncHook.js
index 74d321a6..e735c624 100644
--- a/test/asyncHook.js
+++ b/test/asyncHook.js
@@ -266,92 +266,4 @@ describe('async hook tests', () => {
 
     expect(result.current).toBe('third')
   })
-
-  test('should wait for expectation to pass (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
-
-    expect(result.current).toBe('first')
-
-    let complete = false
-    await wait(() => {
-      expect(result.current).toBe('third')
-      complete = true
-    })
-    expect(complete).toBe(true)
-  })
-
-  test('should not hang if expectation is already passing (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second'))
-
-    expect(result.current).toBe('first')
-
-    let complete = false
-    await wait(() => {
-      expect(result.current).toBe('first')
-      complete = true
-    })
-    expect(complete).toBe(true)
-  })
-
-  test('should reject if callback throws error (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
-
-    expect(result.current).toBe('first')
-
-    await expect(
-      wait(
-        () => {
-          if (result.current === 'second') {
-            throw new Error('Something Unexpected')
-          }
-          return result.current === 'third'
-        },
-        {
-          suppressErrors: false
-        }
-      )
-    ).rejects.toThrow(Error('Something Unexpected'))
-  })
-
-  test('should reject if callback immediately throws error (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
-
-    expect(result.current).toBe('first')
-
-    await expect(
-      wait(
-        () => {
-          throw new Error('Something Unexpected')
-        },
-        {
-          suppressErrors: false
-        }
-      )
-    ).rejects.toThrow(Error('Something Unexpected'))
-  })
-
-  test('should wait for truthy value (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
-
-    expect(result.current).toBe('first')
-
-    await wait(() => result.current === 'third')
-
-    expect(result.current).toBe('third')
-  })
-
-  test('should reject if timeout exceeded when waiting for expectation to pass (deprecated)', async () => {
-    const { result, wait } = renderHook(() => useSequence('first', 'second', 'third'))
-
-    expect(result.current).toBe('first')
-
-    await expect(
-      wait(
-        () => {
-          expect(result.current).toBe('third')
-        },
-        { timeout: 75 }
-      )
-    ).rejects.toThrow(Error('Timed out in wait after 75ms.'))
-  })
 })

From f58e7f00bca4b0dd73d805505b53a5298b57e624 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Fri, 11 Dec 2020 07:56:02 +1100
Subject: [PATCH 08/56] Fix incorrect cleanup callback type

---
 src/cleanup.ts | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/cleanup.ts b/src/cleanup.ts
index 7972347f..a9385eff 100644
--- a/src/cleanup.ts
+++ b/src/cleanup.ts
@@ -1,4 +1,4 @@
-let cleanupCallbacks: (() => Promise<void>)[] = []
+let cleanupCallbacks: (() => Promise<void> | void)[] = []
 
 async function cleanup() {
   for (const callback of cleanupCallbacks) {
@@ -7,12 +7,12 @@ async function cleanup() {
   cleanupCallbacks = []
 }
 
-function addCleanup(callback: () => Promise<void>) {
+function addCleanup(callback: () => Promise<void> | void) {
   cleanupCallbacks.unshift(callback)
   return () => removeCleanup(callback)
 }
 
-function removeCleanup(callback: () => Promise<void>) {
+function removeCleanup(callback: () => Promise<void> | void) {
   cleanupCallbacks = cleanupCallbacks.filter((cb) => cb !== callback)
 }
 

From a8ece2989023253a625c72c0043ea2ebbfe0c8d9 Mon Sep 17 00:00:00 2001
From: tigerabrodi <tigerabrodi@gmail.com>
Date: Thu, 10 Dec 2020 22:31:18 +0100
Subject: [PATCH 09/56] asyncUtils has been updated. Two lines are disabled for
 eslint.

---
 src/asyncUtils.ts | 33 +++++++++++++++------------------
 1 file changed, 15 insertions(+), 18 deletions(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index 864f38c5..c34dec50 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -11,8 +11,7 @@ class TimeoutError extends Error {
 }
 
 function createTimeoutError(utilName: string, { timeout }: Pick<WaitOptions, 'timeout'>) {
-  //eslint-disable-next-line
-  const timeoutError = new TimeoutError(`Timed out in ${utilName} after ${timeout}ms.`)
+  const timeoutError = new TimeoutError(`Timed out in ${utilName} after ${timeout as number}ms.`)
   return timeoutError
 }
 
@@ -22,9 +21,8 @@ function resolveAfter(ms: number) {
   })
 }
 
-// eslint-disable-next-line
-function asyncUtils(addResolver: any) {
-  let nextUpdatePromise: Promise<void | undefined> | null = null
+function asyncUtils(addResolver: (callback: () => void) => void) {
+  let nextUpdatePromise: Promise<void> | null = null
 
   const waitForNextUpdate = async (options: Pick<WaitOptions, 'timeout'> = {}) => {
     if (!nextUpdatePromise) {
@@ -42,14 +40,13 @@ function asyncUtils(addResolver: any) {
           resolve()
         })
       })
-      // eslint-disable-next-line
-      await act(() => nextUpdatePromise!)
+      await act(() => nextUpdatePromise as Promise<void>)
     }
     await nextUpdatePromise
   }
 
-  const waitFor = async (
-    callback: () => boolean | void | undefined,
+  const waitFor = async <T>(
+    callback: () => T | Promise<T> | null,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}
   ) => {
     // eslint-disable-next-line consistent-return
@@ -57,16 +54,16 @@ function asyncUtils(addResolver: any) {
       try {
         const callbackResult = callback()
         return callbackResult ?? callbackResult === undefined
-      } catch (e) {
+      } catch (error: unknown) {
         if (!suppressErrors) {
-          throw e
+          throw error as Error
         }
       }
     }
 
     const waitForResult = async () => {
       const initialTimeout = timeout
-      // eslint-disable-next-line
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
       while (true) {
         const startTime = Date.now()
         try {
@@ -79,11 +76,11 @@ function asyncUtils(addResolver: any) {
           if (checkResult()) {
             return
           }
-        } catch (e) {
-          if (e.timeout) {
+        } catch (error: unknown) {
+          if (error instanceof TimeoutError) {
             throw createTimeoutError('waitFor', { timeout: initialTimeout })
           }
-          throw e
+          throw error as Error
         }
         if (timeout) timeout -= Date.now() - startTime
       }
@@ -101,11 +98,11 @@ function asyncUtils(addResolver: any) {
         suppressErrors: false,
         ...options
       })
-    } catch (e) {
-      if (e.timeout) {
+    } catch (error: unknown) {
+      if (error instanceof TimeoutError) {
         throw createTimeoutError('waitForValueToChange', options)
       }
-      throw e
+      throw error as Error
     }
   }
 

From 7e45893780dd6875fd94c31ba551f413c80d5af6 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Fri, 11 Dec 2020 00:26:23 +0200
Subject: [PATCH 10/56] remove unnecessary eslint disable

---
 src/pure.js | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pure.js b/src/pure.js
index c165fc19..435d0736 100644
--- a/src/pure.js
+++ b/src/pure.js
@@ -1,8 +1,6 @@
 import React, { Suspense } from 'react'
 import { act, create } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
-// TODO: remove this line when it's converted to typescript
-// eslint-disable-next-line import/no-unresolved
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
 function TestHook({ callback, hookProps, onError, children }) {

From b8ddea3066caedf1b726272d216461f859b2f85a Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 18:52:36 -0600
Subject: [PATCH 11/56] Prettier was stripping try catch types - see:
 https://prettier.io/blog/2020/08/24/2.1.0.html\#type-annotations-on-catch-clauses-8805httpsgithubcomprettierprettierpull8805-by-fiskerhttpsgithubcomfisker
 - Updated prettier in local devDeps to resolve directly to newest supported
 version

---
 package.json | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/package.json b/package.json
index 24eb78b1..6cc8d613 100644
--- a/package.json
+++ b/package.json
@@ -47,11 +47,12 @@
     "docz": "2.3.1",
     "docz-theme-default": "1.2.0",
     "docz-utils": "2.3.0",
+    "eslint": "7.15.0",
     "kcd-scripts": "7.5.2",
+    "prettier": "^2.2.1",
     "react": "17.0.1",
     "react-test-renderer": "17.0.1",
-    "typescript": "4.1.2",
-    "eslint": "7.15.0"
+    "typescript": "4.1.2"
   },
   "peerDependencies": {
     "react": ">=16.9.0",

From 44452739ef4956424ede9e7fb6fee17ec4b55060 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 19:34:24 -0600
Subject: [PATCH 12/56] Type for callback handle generic input & undefined
 handled by nullish operator TS expecting explicit return of undefined from
 arrow function with type Expected to return a value at the end of arrow
 function.eslintconsistent-return resolved by passing return in catch with
 undefined, same behavior more explicit

---
 src/asyncUtils.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index c34dec50..f09cfb70 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -46,10 +46,9 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
   }
 
   const waitFor = async <T>(
-    callback: () => T | Promise<T> | null,
+    callback: () => T | Promise<T> | undefined,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}
   ) => {
-    // eslint-disable-next-line consistent-return
     const checkResult = () => {
       try {
         const callbackResult = callback()
@@ -58,6 +57,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
         if (!suppressErrors) {
           throw error as Error
         }
+        return undefined
       }
     }
 

From 05e9a388c419b3aa4155087a40e07117c8f5993e Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 19:37:20 -0600
Subject: [PATCH 13/56] comments for review

---
 src/asyncUtils.ts | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index f09cfb70..fd392ff7 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -45,6 +45,8 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
     await nextUpdatePromise
   }
 
+  // TODO: Discuss with Kent and Maintainers about behavior of returning nothing currently there are tests handling this behavior that may be an anti-pattern.
+  // ? Should waitFor() always expect something returned
   const waitFor = async <T>(
     callback: () => T | Promise<T> | undefined,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}

From 6879cfdbd1c3a18bb96ba2c459afe7988a196180 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 19:54:39 -0600
Subject: [PATCH 14/56] VoidFunction in place for void until decided behavior
 for waitFor()

---
 src/asyncUtils.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index fd392ff7..214eb50c 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -48,7 +48,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
   // TODO: Discuss with Kent and Maintainers about behavior of returning nothing currently there are tests handling this behavior that may be an anti-pattern.
   // ? Should waitFor() always expect something returned
   const waitFor = async <T>(
-    callback: () => T | Promise<T> | undefined,
+    callback: () => T | Promise<T> | undefined | VoidFunction,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}
   ) => {
     const checkResult = () => {

From 8f902ea4cf796dcf201e922ca9e67dcaf91d4c60 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 20:04:23 -0600
Subject: [PATCH 15/56] Utilizing OR operator with generic Types allows for
 desired behavior and previous tests pass

---
 src/asyncUtils.ts | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index 214eb50c..bdf23a40 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -48,13 +48,13 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
   // TODO: Discuss with Kent and Maintainers about behavior of returning nothing currently there are tests handling this behavior that may be an anti-pattern.
   // ? Should waitFor() always expect something returned
   const waitFor = async <T>(
-    callback: () => T | Promise<T> | undefined | VoidFunction,
+    callback: () => T | Promise<T>,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}
   ) => {
     const checkResult = () => {
       try {
         const callbackResult = callback()
-        return callbackResult ?? callbackResult === undefined
+        return callbackResult || callbackResult === undefined
       } catch (error: unknown) {
         if (!suppressErrors) {
           throw error as Error
@@ -65,7 +65,6 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
 
     const waitForResult = async () => {
       const initialTimeout = timeout
-      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
       while (true) {
         const startTime = Date.now()
         try {

From 2c2908bf79294d0d23679e47e39eca9859b21642 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 20:08:53 -0600
Subject: [PATCH 16/56] mistakenly left out linter ignores in last commit

---
 src/asyncUtils.ts | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index bdf23a40..f71973a3 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -65,6 +65,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
 
     const waitForResult = async () => {
       const initialTimeout = timeout
+      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
       while (true) {
         const startTime = Date.now()
         try {

From 58b9b37d3b637ec038c6220b63d198d982e24d07 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Thu, 10 Dec 2020 22:50:35 -0600
Subject: [PATCH 17/56] Minimum types started for Pure file - File needs
 better, improved typing and Refactoring for Linter Disables to be removed IF
 POSSIBLE

---
 src/{pure.js => pure.tsx} | 44 ++++++++++++++++++++++++++-------------
 tsconfig.json             |  4 +++-
 2 files changed, 32 insertions(+), 16 deletions(-)
 rename src/{pure.js => pure.tsx} (51%)

diff --git a/src/pure.js b/src/pure.tsx
similarity index 51%
rename from src/pure.js
rename to src/pure.tsx
index 435d0736..fc061892 100644
--- a/src/pure.js
+++ b/src/pure.tsx
@@ -1,12 +1,18 @@
-import React, { Suspense } from 'react'
-import { act, create } from 'react-test-renderer'
+import React, { ReactElement, ReactNode, Suspense } from 'react'
+import { act, create, ReactTestRenderer } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
-function TestHook({ callback, hookProps, onError, children }) {
+
+// TODO: Add better type, currently file is utilizing minimum types to work
+// TODO: Attempt to refactor code to remove ESLint disables if possible
+type Props = {callback: (arg: unknown) => {}, hookProps: unknown, onError: CallableFunction, children: CallableFunction}
+function TestHook({ callback, hookProps, onError, children }: Props) {
   try {
     children(callback(hookProps))
+  // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
   } catch (err) {
+    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
     if (err.then) {
       throw err
     } else {
@@ -21,8 +27,8 @@ function Fallback() {
 }
 
 function resultContainer() {
-  const results = []
-  const resolvers = []
+  const results: Array<Record<string, unknown>> = [] 
+  const resolvers: Array<VoidFunction> = []
 
   const result = {
     get all() {
@@ -41,26 +47,26 @@ function resultContainer() {
     }
   }
 
-  const updateResult = (value, error) => {
+  const updateResult = (value: unknown, error?: unknown) => {
     results.push({ value, error })
     resolvers.splice(0, resolvers.length).forEach((resolve) => resolve())
   }
 
   return {
     result,
-    addResolver: (resolver) => {
+    addResolver: (resolver: VoidFunction) => {
       resolvers.push(resolver)
     },
-    setValue: (value) => updateResult(value),
-    setError: (error) => updateResult(undefined, error)
+    setValue: (value: unknown) => updateResult(value),
+    setError: (error: unknown) => updateResult(undefined, error)
   }
 }
 
-function renderHook(callback, { initialProps, wrapper } = {}) {
+function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: (React.InputHTMLAttributes<HTMLInputElement> & React.ClassAttributes<HTMLInputElement>) , wrapper?: React.ComponentType} = {}) {
   const { result, setValue, setError, addResolver } = resultContainer()
   const hookProps = { current: initialProps }
 
-  const wrapUiIfNeeded = (innerElement) =>
+  const wrapUiIfNeeded = (innerElement: ReactNode) =>
     wrapper ? React.createElement(wrapper, hookProps.current, innerElement) : innerElement
 
   const toRender = () =>
@@ -70,22 +76,30 @@ function renderHook(callback, { initialProps, wrapper } = {}) {
           {setValue}
         </TestHook>
       </Suspense>
-    )
+    ) as ReactElement 
+
+  
 
-  let testRenderer
-  act(() => {
+
+  // eslint-disable-next-line no-undef-init
+  let testRenderer: ReactTestRenderer | undefined
+    // eslint-disable-next-line @typescript-eslint/no-floating-promises
+    act(() => {
     testRenderer = create(toRender())
   })
-  const { unmount, update } = testRenderer
+  // eslint-disable-next-line @typescript-eslint/unbound-method
+  const { unmount, update } = testRenderer as ReactTestRenderer
 
   function rerenderHook(newProps = hookProps.current) {
     hookProps.current = newProps
+    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
       update(toRender())
     })
   }
 
   function unmountHook() {
+    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
       removeCleanup(unmountHook)
       unmount()
diff --git a/tsconfig.json b/tsconfig.json
index 9fdd876b..a4ae1f0e 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,6 +1,8 @@
 {
+  
   "extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
   "compilerOptions": {
-    "allowJs": true
+    "allowJs": true,
+    "target": "ES6"
   }
 }

From 4818cedbffa1f3234d5ee5efab99df79ec16b62b Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 13:53:35 -0600
Subject: [PATCH 18/56] removed comments -- answered in PR - Types and OR check
 should handle expected behavior

---
 src/asyncUtils.ts | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index f71973a3..a7732d11 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -45,8 +45,6 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
     await nextUpdatePromise
   }
 
-  // TODO: Discuss with Kent and Maintainers about behavior of returning nothing currently there are tests handling this behavior that may be an anti-pattern.
-  // ? Should waitFor() always expect something returned
   const waitFor = async <T>(
     callback: () => T | Promise<T>,
     { interval, timeout, suppressErrors = true }: WaitOptions = {}

From 4c8d1e21391838a69e41359b3d479097d684b5f8 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 14:07:14 -0600
Subject: [PATCH 19/56] Generic HTML types for initialProps

---
 src/pure.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index fc061892..a7c02882 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -62,7 +62,7 @@ function resultContainer() {
   }
 }
 
-function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: (React.InputHTMLAttributes<HTMLInputElement> & React.ClassAttributes<HTMLInputElement>) , wrapper?: React.ComponentType} = {}) {
+function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: (React.HTMLAttributes<HTMLElement> & React.ClassAttributes<HTMLElement>) , wrapper?: React.ComponentType} = {}) {
   const { result, setValue, setError, addResolver } = resultContainer()
   const hookProps = { current: initialProps }
 

From 3f9d853691c111071a7cdae1969777377fea79aa Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 14:08:34 -0600
Subject: [PATCH 20/56] Generic HTML types for initialProps

---
 src/pure.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index a7c02882..75dda9c6 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -62,7 +62,7 @@ function resultContainer() {
   }
 }
 
-function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: (React.HTMLAttributes<HTMLElement> & React.ClassAttributes<HTMLElement>) , wrapper?: React.ComponentType} = {}) {
+function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: T , wrapper?: React.ComponentType} = {}) {
   const { result, setValue, setError, addResolver } = resultContainer()
   const hookProps = { current: initialProps }
 

From d2dadf555bfcb6d35731454c1a2aec5379cc978a Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 14:18:48 -0600
Subject: [PATCH 21/56] Generic type for callback and initialProps

---
 src/pure.tsx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index 75dda9c6..62020f66 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -62,7 +62,7 @@ function resultContainer() {
   }
 }
 
-function renderHook(callback: () => {}, { initialProps, wrapper }: {initialProps?: T , wrapper?: React.ComponentType} = {}) {
+function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps, wrapper }: {initialProps?: T , wrapper?: React.ComponentType} = {}) {
   const { result, setValue, setError, addResolver } = resultContainer()
   const hookProps = { current: initialProps }
 

From 1dba932683cf271f7023fe68081755e6a1b5d230 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 14:54:19 -0600
Subject: [PATCH 22/56] Generics added and CB toplevel same generic pattern
 added

---
 .eslintrc    | 8 +++++++-
 src/pure.tsx | 5 ++++-
 2 files changed, 11 insertions(+), 2 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index a9ed07f2..04b7604d 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -6,6 +6,12 @@
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
-    "import/no-unresolved": "off"
+    "import/no-unresolved": "off",
+    "@typescript-eslint/unbound-method": [
+      "error",
+      {
+        "ignoreStatic": true
+      }
+    ]
   }
 }
diff --git a/src/pure.tsx b/src/pure.tsx
index 62020f66..9c602ef3 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -6,7 +6,8 @@ import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
 // TODO: Add better type, currently file is utilizing minimum types to work
 // TODO: Attempt to refactor code to remove ESLint disables if possible
-type Props = {callback: (arg: unknown) => {}, hookProps: unknown, onError: CallableFunction, children: CallableFunction}
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+type Props<T = any, R =any> = {callback: (props: T) => R, hookProps: unknown, onError: CallableFunction, children: CallableFunction}
 function TestHook({ callback, hookProps, onError, children }: Props) {
   try {
     children(callback(hookProps))
@@ -62,6 +63,7 @@ function resultContainer() {
   }
 }
 
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
 function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps, wrapper }: {initialProps?: T , wrapper?: React.ComponentType} = {}) {
   const { result, setValue, setError, addResolver } = resultContainer()
   const hookProps = { current: initialProps }
@@ -87,6 +89,7 @@ function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps,
     act(() => {
     testRenderer = create(toRender())
   })
+
   // eslint-disable-next-line @typescript-eslint/unbound-method
   const { unmount, update } = testRenderer as ReactTestRenderer
 

From 6b19d1b1370ace34abc0b7c30aec17826f911787 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 19:20:45 -0600
Subject: [PATCH 23/56] force rebuild with unbound method eslint ignore

---
 src/pure.tsx | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index 9c602ef3..a0bb4f0c 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -89,7 +89,6 @@ function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps,
     act(() => {
     testRenderer = create(toRender())
   })
-
   // eslint-disable-next-line @typescript-eslint/unbound-method
   const { unmount, update } = testRenderer as ReactTestRenderer
 

From 9604dd7c980ddafcb04472bef7f2681d40a80806 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 19:25:10 -0600
Subject: [PATCH 24/56] parser issue -- attempt to fix by removing specific TS
 eslint rule

---
 .eslintrc | 6 ------
 1 file changed, 6 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index 04b7604d..1c3e6721 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -7,11 +7,5 @@
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
     "import/no-unresolved": "off",
-    "@typescript-eslint/unbound-method": [
-      "error",
-      {
-        "ignoreStatic": true
-      }
-    ]
   }
 }

From b84a0de3b279cd4e64eda0017a84e2da3496b115 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 19:25:59 -0600
Subject: [PATCH 25/56] Newer versions of ESLint might resolve the parser issue

---
 .eslintrc | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/.eslintrc b/.eslintrc
index 1c3e6721..a9ed07f2 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -6,6 +6,6 @@
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
-    "import/no-unresolved": "off",
+    "import/no-unresolved": "off"
   }
 }

From 319cbba24a1406a918f31bbf654eef8c41e80d0a Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Fri, 11 Dec 2020 19:57:34 -0600
Subject: [PATCH 26/56] Added configs to get started on test conversion

---
 .eslintrc      | 2 +-
 jest.config.js | 2 +-
 tsconfig.json  | 5 +++--
 3 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index a9ed07f2..d80c5b77 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,5 +1,5 @@
 {
-  "extends": "./node_modules/kcd-scripts/eslint.js",
+  "extends":[ "./node_modules/kcd-scripts/eslint.js"],
   "rules": {
     "max-lines-per-function": "off",
     "no-constant-condition": "off",
diff --git a/jest.config.js b/jest.config.js
index 46c43d71..bb6a1d85 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -3,5 +3,5 @@ const { jest: jestConfig } = require('kcd-scripts/config')
 
 module.exports = Object.assign(jestConfig, {
   roots: ['<rootDir>/src', '<rootDir>/test'],
-  testMatch: ['<rootDir>/test/*.js']
+  testMatch: ['<rootDir>/test/*.(ts|tsx|js)']
 })
diff --git a/tsconfig.json b/tsconfig.json
index a4ae1f0e..81cc29e6 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -3,6 +3,7 @@
   "extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
   "compilerOptions": {
     "allowJs": true,
-    "target": "ES6"
-  }
+    "target": "ES6",
+  },
+  "include": ["./test"]
 }

From ec18c2a58a4dec442f1bc5bfe0ce553f84596d69 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Sat, 12 Dec 2020 16:10:44 +0200
Subject: [PATCH 27/56] Generic type for resultContainer

this should allow typescript to infer the type of result.current
further improvments needed to add type guards
---
 src/pure.tsx | 38 +++++++++++++++++++++-----------------
 1 file changed, 21 insertions(+), 17 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index a0bb4f0c..cf2782ad 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -3,15 +3,19 @@ import { act, create, ReactTestRenderer } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
-
 // TODO: Add better type, currently file is utilizing minimum types to work
 // TODO: Attempt to refactor code to remove ESLint disables if possible
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-type Props<T = any, R =any> = {callback: (props: T) => R, hookProps: unknown, onError: CallableFunction, children: CallableFunction}
+type Props<T = any, R = any> = {
+  callback: (props: T) => R
+  hookProps: unknown
+  onError: CallableFunction
+  children: CallableFunction
+}
 function TestHook({ callback, hookProps, onError, children }: Props) {
   try {
     children(callback(hookProps))
-  // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
+    // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
   } catch (err) {
     // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
     if (err.then) {
@@ -27,13 +31,13 @@ function Fallback() {
   return null
 }
 
-function resultContainer() {
-  const results: Array<Record<string, unknown>> = [] 
+function resultContainer<R>() {
+  const results: Array<{ value?: R; error?: Error }> = []
   const resolvers: Array<VoidFunction> = []
 
   const result = {
     get all() {
-      return results.map(({ value, error }) => error || value)
+      return results.map(({ value, error }) => error ?? value)
     },
     get current() {
       const { value, error } = results[results.length - 1]
@@ -48,7 +52,7 @@ function resultContainer() {
     }
   }
 
-  const updateResult = (value: unknown, error?: unknown) => {
+  const updateResult = (value?: R, error?: Error) => {
     results.push({ value, error })
     resolvers.splice(0, resolvers.length).forEach((resolve) => resolve())
   }
@@ -58,14 +62,17 @@ function resultContainer() {
     addResolver: (resolver: VoidFunction) => {
       resolvers.push(resolver)
     },
-    setValue: (value: unknown) => updateResult(value),
-    setError: (error: unknown) => updateResult(undefined, error)
+    setValue: (value: R) => updateResult(value),
+    setError: (error: Error) => updateResult(undefined, error)
   }
 }
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps, wrapper }: {initialProps?: T , wrapper?: React.ComponentType} = {}) {
-  const { result, setValue, setError, addResolver } = resultContainer()
+function renderHook<T = any, R = any>(
+  callback: (props: T) => R,
+  { initialProps, wrapper }: { initialProps?: T; wrapper?: React.ComponentType } = {}
+) {
+  const { result, setValue, setError, addResolver } = resultContainer<R>()
   const hookProps = { current: initialProps }
 
   const wrapUiIfNeeded = (innerElement: ReactNode) =>
@@ -78,15 +85,12 @@ function renderHook<T = any, R = any>(callback: (props: T) => R, { initialProps,
           {setValue}
         </TestHook>
       </Suspense>
-    ) as ReactElement 
-
-  
-
+    ) as ReactElement
 
   // eslint-disable-next-line no-undef-init
   let testRenderer: ReactTestRenderer | undefined
-    // eslint-disable-next-line @typescript-eslint/no-floating-promises
-    act(() => {
+  // eslint-disable-next-line @typescript-eslint/no-floating-promises
+  act(() => {
     testRenderer = create(toRender())
   })
   // eslint-disable-next-line @typescript-eslint/unbound-method

From 7c8ddee84403a484dcd6d98f27716161801b4e36 Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Sat, 12 Dec 2020 16:33:41 +0200
Subject: [PATCH 28/56] convert tests that require no changes

renamed tests that didn't require code changes to the tests
---
 test/{asyncHook.js => asyncHook.ts}         | 2 +-
 test/{autoCleanup.js => autoCleanup.ts}     | 0
 test/{resultHistory.js => resultHistory.ts} | 0
 3 files changed, 1 insertion(+), 1 deletion(-)
 rename test/{asyncHook.js => asyncHook.ts} (99%)
 rename test/{autoCleanup.js => autoCleanup.ts} (100%)
 rename test/{resultHistory.js => resultHistory.ts} (100%)

diff --git a/test/asyncHook.js b/test/asyncHook.ts
similarity index 99%
rename from test/asyncHook.js
rename to test/asyncHook.ts
index e735c624..5479db82 100644
--- a/test/asyncHook.js
+++ b/test/asyncHook.ts
@@ -2,7 +2,7 @@ import { useState, useRef, useEffect } from 'react'
 import { renderHook } from '../src'
 
 describe('async hook tests', () => {
-  const useSequence = (...values) => {
+  const useSequence = (...values: string[]) => {
     const [first, ...otherValues] = values
     const [value, setValue] = useState(first)
     const index = useRef(0)
diff --git a/test/autoCleanup.js b/test/autoCleanup.ts
similarity index 100%
rename from test/autoCleanup.js
rename to test/autoCleanup.ts
diff --git a/test/resultHistory.js b/test/resultHistory.ts
similarity index 100%
rename from test/resultHistory.js
rename to test/resultHistory.ts

From e3ecb248ece038a737bcfde5e75899acd4bf3c0a Mon Sep 17 00:00:00 2001
From: Amr Gad <merodiro@gmail.com>
Date: Sat, 12 Dec 2020 17:21:12 +0200
Subject: [PATCH 29/56] add types to cleanup test

---
 test/{cleanup.js => cleanup.ts} | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)
 rename test/{cleanup.js => cleanup.ts} (92%)

diff --git a/test/cleanup.js b/test/cleanup.ts
similarity index 92%
rename from test/cleanup.js
rename to test/cleanup.ts
index 05dba6dc..1eafffbf 100644
--- a/test/cleanup.js
+++ b/test/cleanup.ts
@@ -21,8 +21,8 @@ describe('cleanup tests', () => {
   })
 
   test('should cleanup all rendered hooks', async () => {
-    const cleanupCalled = []
-    const hookWithCleanup = (id) => {
+    const cleanupCalled: boolean[] = []
+    const hookWithCleanup = (id: number) => {
       useEffect(() => {
         return () => {
           cleanupCalled[id] = true
@@ -40,7 +40,7 @@ describe('cleanup tests', () => {
   })
 
   test('should call cleanups in reverse order', async () => {
-    const callSequence = []
+    const callSequence: string[] = []
     addCleanup(() => {
       callSequence.push('cleanup')
     })
@@ -62,7 +62,7 @@ describe('cleanup tests', () => {
   })
 
   test('should wait for async cleanup', async () => {
-    const callSequence = []
+    const callSequence: string[] = []
     addCleanup(() => {
       callSequence.push('cleanup')
     })
@@ -85,7 +85,7 @@ describe('cleanup tests', () => {
   })
 
   test('should remove cleanup using removeCleanup', async () => {
-    const callSequence = []
+    const callSequence: string[] = []
     addCleanup(() => {
       callSequence.push('cleanup')
     })
@@ -110,7 +110,7 @@ describe('cleanup tests', () => {
   })
 
   test('should remove cleanup using returned handler', async () => {
-    const callSequence = []
+    const callSequence: string[] = []
     addCleanup(() => {
       callSequence.push('cleanup')
     })

From d74e947032f175712ae43c2215e5eb018bb64173 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Sat, 12 Dec 2020 12:34:36 -0600
Subject: [PATCH 30/56] Test TS Overhaul - Amr, Tiger and myself worked on
 these commits - Other Raid members in chat assisted - All tests are strongly
 typed with minimal types to allow for working and made sure tests types were
 easily usable with types in Pure and Utils file, allow for good UX & DX

---
 src/pure.tsx                                             | 4 ++--
 .../{autoCleanup.disabled.js => autoCleanup.disabled.ts} | 2 +-
 ...Cleanup.noAfterEach.js => autoCleanup.noAfterEach.ts} | 3 ++-
 test/{customHook.js => customHook.ts}                    | 1 +
 test/{errorHook.js => errorHook.ts}                      | 9 +++++----
 test/{suspenseHook.js => suspenseHook.ts}                | 9 +++++----
 test/{useContext.js => useContext.tsx}                   | 7 ++++---
 test/{useEffect.js => useEffect.ts}                      | 0
 test/{useMemo.js => useMemo.ts}                          | 0
 test/{useReducer.js => useReducer.ts}                    | 4 +++-
 test/{useRef.js => useRef.ts}                            | 2 +-
 test/{useState.js => useState.ts}                        | 6 ++++--
 12 files changed, 28 insertions(+), 19 deletions(-)
 rename test/{autoCleanup.disabled.js => autoCleanup.disabled.ts} (93%)
 rename test/{autoCleanup.noAfterEach.js => autoCleanup.noAfterEach.ts} (84%)
 rename test/{customHook.js => customHook.ts} (92%)
 rename test/{errorHook.js => errorHook.ts} (94%)
 rename test/{suspenseHook.js => suspenseHook.ts} (77%)
 rename test/{useContext.js => useContext.tsx} (89%)
 rename test/{useEffect.js => useEffect.ts} (100%)
 rename test/{useMemo.js => useMemo.ts} (100%)
 rename test/{useReducer.js => useReducer.ts} (69%)
 rename test/{useRef.js => useRef.ts} (91%)
 rename test/{useState.js => useState.ts} (77%)

diff --git a/src/pure.tsx b/src/pure.tsx
index cf2782ad..fb246100 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -44,7 +44,7 @@ function resultContainer<R>() {
       if (error) {
         throw error
       }
-      return value
+      return value as R
     },
     get error() {
       const { error } = results[results.length - 1]
@@ -70,7 +70,7 @@ function resultContainer<R>() {
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 function renderHook<T = any, R = any>(
   callback: (props: T) => R,
-  { initialProps, wrapper }: { initialProps?: T; wrapper?: React.ComponentType } = {}
+  { initialProps, wrapper }: { initialProps?: T; wrapper?: React.ComponentType<T> } = {}
 ) {
   const { result, setValue, setError, addResolver } = resultContainer<R>()
   const hookProps = { current: initialProps }
diff --git a/test/autoCleanup.disabled.js b/test/autoCleanup.disabled.ts
similarity index 93%
rename from test/autoCleanup.disabled.js
rename to test/autoCleanup.disabled.ts
index 174a3135..35cbf91a 100644
--- a/test/autoCleanup.disabled.js
+++ b/test/autoCleanup.disabled.ts
@@ -4,7 +4,7 @@ import { useEffect } from 'react'
 // then we DON'T auto-wire up the afterEach for folks
 describe('skip auto cleanup (disabled) tests', () => {
   let cleanupCalled = false
-  let renderHook
+  let renderHook: (arg0: () => void) => void
 
   beforeAll(() => {
     process.env.RHTL_SKIP_AUTO_CLEANUP = 'true'
diff --git a/test/autoCleanup.noAfterEach.js b/test/autoCleanup.noAfterEach.ts
similarity index 84%
rename from test/autoCleanup.noAfterEach.js
rename to test/autoCleanup.noAfterEach.ts
index 2531c657..cd30a841 100644
--- a/test/autoCleanup.noAfterEach.js
+++ b/test/autoCleanup.noAfterEach.ts
@@ -4,9 +4,10 @@ import { useEffect } from 'react'
 // then we DON'T auto-wire up the afterEach for folks
 describe('skip auto cleanup (no afterEach) tests', () => {
   let cleanupCalled = false
-  let renderHook
+  let renderHook: (arg0: () => void) => void
 
   beforeAll(() => {
+    // @ts-expect-error Turning off AfterEach -- ignore Jest LifeCycle Type
     // eslint-disable-next-line no-global-assign
     afterEach = false
     // eslint-disable-next-line
diff --git a/test/customHook.js b/test/customHook.ts
similarity index 92%
rename from test/customHook.js
rename to test/customHook.ts
index 871c5619..4875efee 100644
--- a/test/customHook.js
+++ b/test/customHook.ts
@@ -1,3 +1,4 @@
+/* eslint-disable @typescript-eslint/no-floating-promises */
 import { useState, useCallback } from 'react'
 import { renderHook, act } from '../src'
 
diff --git a/test/errorHook.js b/test/errorHook.ts
similarity index 94%
rename from test/errorHook.js
rename to test/errorHook.ts
index 55e425e2..811c1b7b 100644
--- a/test/errorHook.js
+++ b/test/errorHook.ts
@@ -1,16 +1,17 @@
 import { useState, useEffect } from 'react'
 import { renderHook } from '../src'
 
+type throwError = Error | boolean | undefined
 describe('error hook tests', () => {
-  function useError(throwError) {
+  function useError(throwError: throwError) {
     if (throwError) {
       throw new Error('expected')
     }
     return true
   }
 
-  function useAsyncError(throwError) {
-    const [value, setValue] = useState()
+  function useAsyncError(throwError: throwError) {
+    const [value, setValue] = useState<throwError>()
     useEffect(() => {
       const timeout = setTimeout(() => setValue(throwError), 100)
       return () => clearTimeout(timeout)
@@ -18,7 +19,7 @@ describe('error hook tests', () => {
     return useError(value)
   }
 
-  function useEffectError(throwError) {
+  function useEffectError(throwError: throwError) {
     useEffect(() => {
       useError(throwError)
     }, [throwError])
diff --git a/test/suspenseHook.js b/test/suspenseHook.ts
similarity index 77%
rename from test/suspenseHook.js
rename to test/suspenseHook.ts
index 6dcfdeae..2853d13d 100644
--- a/test/suspenseHook.js
+++ b/test/suspenseHook.ts
@@ -1,10 +1,10 @@
 import { renderHook } from '../src'
 
 describe('suspense hook tests', () => {
-  const cache = {}
-  const fetchName = (isSuccessful) => {
+  const cache: { value?: Promise<string> | string | Error } = {}
+  const fetchName = (isSuccessful: boolean) => {
     if (!cache.value) {
-      cache.value = new Promise((resolve, reject) => {
+      cache.value = new Promise<string>((resolve, reject) => {
         setTimeout(() => {
           if (isSuccessful) {
             resolve('Bob')
@@ -21,7 +21,8 @@ describe('suspense hook tests', () => {
 
   const useFetchName = (isSuccessful = true) => {
     const name = fetchName(isSuccessful)
-    if (typeof name.then === 'function' || name instanceof Error) {
+    if (name instanceof Promise || name instanceof Error) {
+      // eslint-disable-next-line @typescript-eslint/no-throw-literal
       throw name
     }
     return name
diff --git a/test/useContext.js b/test/useContext.tsx
similarity index 89%
rename from test/useContext.js
rename to test/useContext.tsx
index 4bcbe774..03bc19f4 100644
--- a/test/useContext.js
+++ b/test/useContext.tsx
@@ -15,7 +15,7 @@ describe('useContext tests', () => {
   test('should get value from context provider', () => {
     const TestContext = createContext('foo')
 
-    const wrapper = ({ children }) => (
+    const wrapper: React.FC = ({ children  } ) => (
       <TestContext.Provider value="bar">{children}</TestContext.Provider>
     )
 
@@ -29,7 +29,7 @@ describe('useContext tests', () => {
 
     const value = { current: 'bar' }
 
-    const wrapper = ({ children }) => (
+    const wrapper: React.FC = ({ children }) => (
       <TestContext.Provider value={value.current}>{children}</TestContext.Provider>
     )
 
@@ -45,7 +45,8 @@ describe('useContext tests', () => {
   test('should update value in context when props are updated', () => {
     const TestContext = createContext('foo')
 
-    const wrapper = ({ current, children }) => (
+
+    const wrapper: React.FC<{current: string}> = ({ current, children }) => (
       <TestContext.Provider value={current}>{children}</TestContext.Provider>
     )
 
diff --git a/test/useEffect.js b/test/useEffect.ts
similarity index 100%
rename from test/useEffect.js
rename to test/useEffect.ts
diff --git a/test/useMemo.js b/test/useMemo.ts
similarity index 100%
rename from test/useMemo.js
rename to test/useMemo.ts
diff --git a/test/useReducer.js b/test/useReducer.ts
similarity index 69%
rename from test/useReducer.js
rename to test/useReducer.ts
index 114f579b..43add078 100644
--- a/test/useReducer.js
+++ b/test/useReducer.ts
@@ -3,13 +3,15 @@ import { renderHook, act } from '../src'
 
 describe('useReducer tests', () => {
   test('should handle useReducer hook', () => {
-    const reducer = (state, action) => (action.type === 'inc' ? state + 1 : state)
+    const reducer = (state: number, action: { type: string }) =>
+      action.type === 'inc' ? state + 1 : state
     const { result } = renderHook(() => useReducer(reducer, 0))
 
     const [initialState, dispatch] = result.current
 
     expect(initialState).toBe(0)
 
+    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => dispatch({ type: 'inc' }))
 
     const [state] = result.current
diff --git a/test/useRef.js b/test/useRef.ts
similarity index 91%
rename from test/useRef.js
rename to test/useRef.ts
index b9dbefe3..6434d77d 100644
--- a/test/useRef.js
+++ b/test/useRef.ts
@@ -13,7 +13,7 @@ describe('useHook tests', () => {
 
   test('should handle useImperativeHandle hook', () => {
     const { result } = renderHook(() => {
-      const ref = useRef()
+      const ref = useRef<Record<string, CallableFunction>>({})
       useImperativeHandle(ref, () => ({
         fakeImperativeMethod: () => true
       }))
diff --git a/test/useState.js b/test/useState.ts
similarity index 77%
rename from test/useState.js
rename to test/useState.ts
index 42f3f8b0..fe7726cf 100644
--- a/test/useState.js
+++ b/test/useState.ts
@@ -5,7 +5,7 @@ describe('useState tests', () => {
   test('should use setState value', () => {
     const { result } = renderHook(() => useState('foo'))
 
-    const [value] = result.current
+    const [value] = result.current 
 
     expect(value).toBe('foo')
   })
@@ -13,9 +13,11 @@ describe('useState tests', () => {
   test('should update setState value using setter', () => {
     const { result } = renderHook(() => useState('foo'))
 
+
     const [ignoredValue, setValue] = result.current
 
-    act(() => setValue('bar'))
+    // eslint-disable-next-line @typescript-eslint/no-floating-promises
+    act(() => setValue('bar')) 
 
     const [value] = result.current
 

From d85fb8511fa443d457a8d41a95f66c25cab69da0 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Sat, 12 Dec 2020 12:44:14 -0600
Subject: [PATCH 31/56] Amr updated types useEffect

---
 test/useEffect.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/useEffect.ts b/test/useEffect.ts
index 9e120e07..266e9aff 100644
--- a/test/useEffect.ts
+++ b/test/useEffect.ts
@@ -6,7 +6,7 @@ describe('useEffect tests', () => {
     const sideEffect = { 1: false, 2: false }
 
     const { rerender, unmount } = renderHook(
-      ({ id }) => {
+      ({ id }: { id: 1 | 2 }) => {
         useEffect(() => {
           sideEffect[id] = true
           return () => {
@@ -35,7 +35,7 @@ describe('useEffect tests', () => {
     const sideEffect = { 1: false, 2: false }
 
     const { rerender, unmount } = renderHook(
-      ({ id }) => {
+      ({ id }: { id: 1 | 2 }) => {
         useLayoutEffect(() => {
           sideEffect[id] = true
           return () => {

From ce607352f87d270c48a65f40b78c10eb9be52f95 Mon Sep 17 00:00:00 2001
From: Jacob Evans <cloud887@gmail.com>
Date: Sat, 12 Dec 2020 12:46:32 -0600
Subject: [PATCH 32/56] Jens suggestion for more generic number key type

---
 test/useEffect.ts | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/test/useEffect.ts b/test/useEffect.ts
index 266e9aff..cad9d0f3 100644
--- a/test/useEffect.ts
+++ b/test/useEffect.ts
@@ -3,10 +3,10 @@ import { renderHook } from '../src'
 
 describe('useEffect tests', () => {
   test('should handle useEffect hook', () => {
-    const sideEffect = { 1: false, 2: false }
+    const sideEffect: { [key: number]: boolean } = { 1: false, 2: false }
 
     const { rerender, unmount } = renderHook(
-      ({ id }: { id: 1 | 2 }) => {
+      ({ id }) => {
         useEffect(() => {
           sideEffect[id] = true
           return () => {
@@ -32,10 +32,10 @@ describe('useEffect tests', () => {
   })
 
   test('should handle useLayoutEffect hook', () => {
-    const sideEffect = { 1: false, 2: false }
+    const sideEffect: { [key: number]: boolean } = { 1: false, 2: false }
 
     const { rerender, unmount } = renderHook(
-      ({ id }: { id: 1 | 2 }) => {
+      ({ id }) => {
         useLayoutEffect(() => {
           sideEffect[id] = true
           return () => {

From 74793cd339fce587d02fa371f8c84e1ec3f1fadd Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Sun, 13 Dec 2020 08:05:21 +1100
Subject: [PATCH 33/56] Remove wait reference from docs

---
 docs/api-reference.md | 25 -------------------------
 1 file changed, 25 deletions(-)

diff --git a/docs/api-reference.md b/docs/api-reference.md
index a3cc05e5..fa7daf4b 100644
--- a/docs/api-reference.md
+++ b/docs/api-reference.md
@@ -259,28 +259,3 @@ The maximum amount of time in milliseconds (ms) to wait. By default, no timeout
 If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
 If this option is set to `false`, any errors that occur while waiting cause the promise to be
 rejected. By default, errors are not suppressed for this utility.
-
-### `wait`
-
-_(DEPRECATED, use [`waitFor`](/reference/api#waitfor) instead)_
-
-```js
-function wait(callback: function(): boolean|void, options?: {
-  timeout?: number,
-  suppressErrors?: boolean
-}): Promise<void>
-```
-
-Returns a `Promise` that resolves if the provided callback executes without exception and returns a
-truthy or `undefined` value. It is safe to use the [`result` of `renderHook`](/reference/api#result)
-in the callback to perform assertion or to test values.
-
-#### `timeout`
-
-The maximum amount of time in milliseconds (ms) to wait. By default, no timeout is applied.
-
-#### `suppressErrors`
-
-If this option is set to `true`, any errors that occur while waiting are treated as a failed check.
-If this option is set to `false`, any errors that occur while waiting cause the promise to be
-rejected. By default, errors are suppressed for this utility.

From acfed0d28bec8656cfc59289a1efa0b238928b3c Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Sun, 13 Dec 2020 08:33:43 +1100
Subject: [PATCH 34/56] Add nobrayner to contributors

---
 .all-contributorsrc | 9 +++++++++
 README.md           | 3 +++
 2 files changed, 12 insertions(+)

diff --git a/.all-contributorsrc b/.all-contributorsrc
index fd2fd14a..1cc172b9 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -212,6 +212,15 @@
       "contributions": [
         "code"
       ]
+    },
+    {
+      "login": "nobrayner",
+      "name": "Braydon Hall",
+      "avatar_url": "https://avatars2.githubusercontent.com/u/40751395?v=4",
+      "profile": "https://github.com/nobrayner",
+      "contributions": [
+        "code"
+      ]
     }
   ],
   "commitConvention": "none"
diff --git a/README.md b/README.md
index 72ef55a9..b6297fe0 100644
--- a/README.md
+++ b/README.md
@@ -192,6 +192,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
     <td align="center"><a href="https://github.com/joshuaellis"><img src="https://avatars0.githubusercontent.com/u/37798644?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Josh</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=joshuaellis" title="Documentation">📖</a></td>
     <td align="center"><a href="https://github.com/Goldziher"><img src="https://avatars1.githubusercontent.com/u/30733348?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Na'aman Hirschfeld</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=Goldziher" title="Code">💻</a></td>
   </tr>
+  <tr>
+    <td align="center"><a href="https://github.com/nobrayner"><img src="https://avatars2.githubusercontent.com/u/40751395?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Braydon Hall</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=nobrayner" title="Code">💻</a></td>
+  </tr>
 </table>
 
 <!-- markdownlint-restore -->

From b77b17af176e971fa6d7030c7125248bdd5a0507 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Sun, 13 Dec 2020 10:33:17 +1100
Subject: [PATCH 35/56] Add JacobMGEvans to contributors

---
 .all-contributorsrc | 10 ++++++++++
 README.md           |  1 +
 2 files changed, 11 insertions(+)

diff --git a/.all-contributorsrc b/.all-contributorsrc
index 1cc172b9..7161db0f 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -221,6 +221,16 @@
       "contributions": [
         "code"
       ]
+    },
+    {
+      "login": "JacobMGEvans",
+      "name": "Jacob M-G Evans",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/27247160?v=4",
+      "profile": "https://dev.to/jacobmgevans",
+      "contributions": [
+        "code",
+        "test"
+      ]
     }
   ],
   "commitConvention": "none"
diff --git a/README.md b/README.md
index b6297fe0..9cd99dce 100644
--- a/README.md
+++ b/README.md
@@ -194,6 +194,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
   </tr>
   <tr>
     <td align="center"><a href="https://github.com/nobrayner"><img src="https://avatars2.githubusercontent.com/u/40751395?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Braydon Hall</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=nobrayner" title="Code">💻</a></td>
+    <td align="center"><a href="https://dev.to/jacobmgevans"><img src="https://avatars1.githubusercontent.com/u/27247160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob M-G Evans</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Tests">⚠️</a></td>
   </tr>
 </table>
 

From b5977f68a3097fe55cc2cf351fcff5a686ddbeed Mon Sep 17 00:00:00 2001
From: Jacob M-G Evans <27247160+JacobMGEvans@users.noreply.github.com>
Date: Sat, 12 Dec 2020 19:01:47 -0600
Subject: [PATCH 36/56] Update src/pure.tsx

---
 src/pure.tsx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index fb246100..e06e6fcb 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -3,8 +3,6 @@ import { act, create, ReactTestRenderer } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
-// TODO: Add better type, currently file is utilizing minimum types to work
-// TODO: Attempt to refactor code to remove ESLint disables if possible
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
 type Props<T = any, R = any> = {
   callback: (props: T) => R

From e6997ca7ee0a2dbad75b77458397bbe0db9f028c Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Sun, 13 Dec 2020 14:21:03 +1100
Subject: [PATCH 37/56] Add tigerabrodi to contributors

---
 .all-contributorsrc | 10 ++++++++++
 README.md           |  1 +
 2 files changed, 11 insertions(+)

diff --git a/.all-contributorsrc b/.all-contributorsrc
index 7161db0f..4bdc0e35 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -231,6 +231,16 @@
         "code",
         "test"
       ]
+    },
+    {
+      "login": "tigerabrodi",
+      "name": "Tiger Abrodi",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/49603590?v=4",
+      "profile": "https://tigerabrodi.dev/",
+      "contributions": [
+        "code",
+        "test"
+      ]
     }
   ],
   "commitConvention": "none"
diff --git a/README.md b/README.md
index 9cd99dce..bc651e46 100644
--- a/README.md
+++ b/README.md
@@ -195,6 +195,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
   <tr>
     <td align="center"><a href="https://github.com/nobrayner"><img src="https://avatars2.githubusercontent.com/u/40751395?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Braydon Hall</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=nobrayner" title="Code">💻</a></td>
     <td align="center"><a href="https://dev.to/jacobmgevans"><img src="https://avatars1.githubusercontent.com/u/27247160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob M-G Evans</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Tests">⚠️</a></td>
+    <td align="center"><a href="https://tigerabrodi.dev/"><img src="https://avatars1.githubusercontent.com/u/49603590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tiger Abrodi</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Tests">⚠️</a></td>
   </tr>
 </table>
 

From 3485a0264c469f343699335e2ea027055e1e1c52 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Sun, 13 Dec 2020 17:02:25 +1100
Subject: [PATCH 38/56] Add Amr, Juhana, and Jens to contributors

---
 .all-contributorsrc | 29 +++++++++++++++++++++++++++++
 README.md           |  3 +++
 2 files changed, 32 insertions(+)

diff --git a/.all-contributorsrc b/.all-contributorsrc
index 4bdc0e35..d7d137c5 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -241,6 +241,35 @@
         "code",
         "test"
       ]
+    },
+    {
+      "login": "merodiro",
+      "name": "Amr A.Mohammed",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/17033502?v=4",
+      "profile": "https://github.com/merodiro",
+      "contributions": [
+        "code",
+        "test"
+      ]
+    },
+    {
+      "login": "juhanakristian",
+      "name": "Juhana Jauhiainen",
+      "avatar_url": "https://avatars1.githubusercontent.com/u/544386?v=4",
+      "profile": "https://github.com/juhanakristian",
+      "contributions": [
+        "code"
+      ]
+    },
+    {
+      "login": "jensmeindertsma",
+      "name": "Jens Meindertsma",
+      "avatar_url": "https://avatars3.githubusercontent.com/u/64677517?v=4",
+      "profile": "https://github.com/jensmeindertsma",
+      "contributions": [
+        "code",
+        "test"
+      ]
     }
   ],
   "commitConvention": "none"
diff --git a/README.md b/README.md
index bc651e46..b62c279d 100644
--- a/README.md
+++ b/README.md
@@ -196,6 +196,9 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
     <td align="center"><a href="https://github.com/nobrayner"><img src="https://avatars2.githubusercontent.com/u/40751395?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Braydon Hall</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=nobrayner" title="Code">💻</a></td>
     <td align="center"><a href="https://dev.to/jacobmgevans"><img src="https://avatars1.githubusercontent.com/u/27247160?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jacob M-G Evans</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=JacobMGEvans" title="Tests">⚠️</a></td>
     <td align="center"><a href="https://tigerabrodi.dev/"><img src="https://avatars1.githubusercontent.com/u/49603590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tiger Abrodi</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=tigerabrodi" title="Tests">⚠️</a></td>
+    <td align="center"><a href="https://github.com/merodiro"><img src="https://avatars1.githubusercontent.com/u/17033502?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Amr A.Mohammed</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=merodiro" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=merodiro" title="Tests">⚠️</a></td>
+    <td align="center"><a href="https://github.com/juhanakristian"><img src="https://avatars1.githubusercontent.com/u/544386?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Juhana Jauhiainen</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=juhanakristian" title="Code">💻</a></td>
+    <td align="center"><a href="https://github.com/jensmeindertsma"><img src="https://avatars3.githubusercontent.com/u/64677517?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Jens Meindertsma</b></sub></a><br /><a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=jensmeindertsma" title="Code">💻</a> <a href="https://github.com/testing-library/react-hooks-testing-library/commits?author=jensmeindertsma" title="Tests">⚠️</a></td>
   </tr>
 </table>
 

From ed2bb4aa2020dcd8c8865df953b9188370153c3a Mon Sep 17 00:00:00 2001
From: tigerabrodi <tigerabrodi@gmail.com>
Date: Sun, 13 Dec 2020 13:42:31 +0100
Subject: [PATCH 39/56] update suspenseHook, cache type and the type of the
 error in catch.

---
 test/suspenseHook.ts | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/test/suspenseHook.ts b/test/suspenseHook.ts
index 2853d13d..c4aef046 100644
--- a/test/suspenseHook.ts
+++ b/test/suspenseHook.ts
@@ -1,7 +1,7 @@
 import { renderHook } from '../src'
 
 describe('suspense hook tests', () => {
-  const cache: { value?: Promise<string> | string | Error } = {}
+  const cache: { value?: Promise<string | Error> | string | Error } = {}
   const fetchName = (isSuccessful: boolean) => {
     if (!cache.value) {
       cache.value = new Promise<string>((resolve, reject) => {
@@ -14,7 +14,7 @@ describe('suspense hook tests', () => {
         }, 50)
       })
         .then((value) => (cache.value = value))
-        .catch((e) => (cache.value = e))
+        .catch((e: Error) => (cache.value = e))
     }
     return cache.value
   }

From 65e4d0cf808cae61d942bbd360666cf24b530546 Mon Sep 17 00:00:00 2001
From: tigerabrodi <tigerabrodi@gmail.com>
Date: Sun, 13 Dec 2020 13:45:32 +0100
Subject: [PATCH 40/56] cleanup.ts, update the way addCleanup adds another
 callback to cleanupCallbacks.

---
 src/cleanup.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/cleanup.ts b/src/cleanup.ts
index a9385eff..8309bd04 100644
--- a/src/cleanup.ts
+++ b/src/cleanup.ts
@@ -8,7 +8,7 @@ async function cleanup() {
 }
 
 function addCleanup(callback: () => Promise<void> | void) {
-  cleanupCallbacks.unshift(callback)
+  cleanupCallbacks = [callback, ...cleanupCallbacks]
   return () => removeCleanup(callback)
 }
 

From d51ddc1d5883e5e59c6b3d449284e5e654161faa Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Mon, 14 Dec 2020 12:42:14 +1100
Subject: [PATCH 41/56] Made generics more descriptive, made TestHook generic

---
 src/pure.tsx | 45 +++++++++++++++++++++++++++------------------
 1 file changed, 27 insertions(+), 18 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index e06e6fcb..07adf9b7 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -4,15 +4,25 @@ import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
 // eslint-disable-next-line @typescript-eslint/no-explicit-any
-type Props<T = any, R = any> = {
-  callback: (props: T) => R
-  hookProps: unknown
-  onError: CallableFunction
-  children: CallableFunction
+type TestHookProps<TProps, TResult> = {
+  callback: (props: TProps) => TResult
+  hookProps: TProps | undefined
+  onError: (error: Error) => void
+  children: (value: TResult) => void
 }
-function TestHook({ callback, hookProps, onError, children }: Props) {
+function TestHook<TProps, TResult>({
+  callback,
+  hookProps,
+  onError,
+  children
+}: TestHookProps<TProps, TResult>) {
   try {
-    children(callback(hookProps))
+    if (hookProps) {
+      children(callback(hookProps))
+    } else {
+      // coerce into undefined, so it maintains the previous behaviour
+      children(callback((undefined as unknown) as TProps))
+    }
     // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
   } catch (err) {
     // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
@@ -29,8 +39,8 @@ function Fallback() {
   return null
 }
 
-function resultContainer<R>() {
-  const results: Array<{ value?: R; error?: Error }> = []
+function resultContainer<TValue>() {
+  const results: Array<{ value?: TValue; error?: Error }> = []
   const resolvers: Array<VoidFunction> = []
 
   const result = {
@@ -42,7 +52,7 @@ function resultContainer<R>() {
       if (error) {
         throw error
       }
-      return value as R
+      return value as TValue
     },
     get error() {
       const { error } = results[results.length - 1]
@@ -50,7 +60,7 @@ function resultContainer<R>() {
     }
   }
 
-  const updateResult = (value?: R, error?: Error) => {
+  const updateResult = (value?: TValue, error?: Error) => {
     results.push({ value, error })
     resolvers.splice(0, resolvers.length).forEach((resolve) => resolve())
   }
@@ -60,17 +70,16 @@ function resultContainer<R>() {
     addResolver: (resolver: VoidFunction) => {
       resolvers.push(resolver)
     },
-    setValue: (value: R) => updateResult(value),
+    setValue: (value: TValue) => updateResult(value),
     setError: (error: Error) => updateResult(undefined, error)
   }
 }
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
-function renderHook<T = any, R = any>(
-  callback: (props: T) => R,
-  { initialProps, wrapper }: { initialProps?: T; wrapper?: React.ComponentType<T> } = {}
+function renderHook<TProps, TResult>(
+  callback: (props: TProps) => TResult,
+  { initialProps, wrapper }: { initialProps?: TProps; wrapper?: React.ComponentType<TProps> } = {}
 ) {
-  const { result, setValue, setError, addResolver } = resultContainer<R>()
+  const { result, setValue, setError, addResolver } = resultContainer<TResult>()
   const hookProps = { current: initialProps }
 
   const wrapUiIfNeeded = (innerElement: ReactNode) =>
@@ -94,7 +103,7 @@ function renderHook<T = any, R = any>(
   // eslint-disable-next-line @typescript-eslint/unbound-method
   const { unmount, update } = testRenderer as ReactTestRenderer
 
-  function rerenderHook(newProps = hookProps.current) {
+  function rerenderHook(newProps: typeof initialProps = hookProps.current) {
     hookProps.current = newProps
     // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {

From fb93f4e11331a86ff12f40809e601016c3f92cd0 Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Mon, 14 Dec 2020 12:46:54 +1100
Subject: [PATCH 42/56] Remove some eslint disables that didn't do anything

---
 src/pure.tsx | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index 07adf9b7..e54c0f72 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -3,7 +3,6 @@ import { act, create, ReactTestRenderer } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
-// eslint-disable-next-line @typescript-eslint/no-explicit-any
 type TestHookProps<TProps, TResult> = {
   callback: (props: TProps) => TResult
   hookProps: TProps | undefined
@@ -94,7 +93,6 @@ function renderHook<TProps, TResult>(
       </Suspense>
     ) as ReactElement
 
-  // eslint-disable-next-line no-undef-init
   let testRenderer: ReactTestRenderer | undefined
   // eslint-disable-next-line @typescript-eslint/no-floating-promises
   act(() => {

From 1779a85b5adc0f0b8b65542848a48947edfd4e3c Mon Sep 17 00:00:00 2001
From: Braydon Hall <40751395+nobrayner@users.noreply.github.com>
Date: Mon, 14 Dec 2020 17:41:50 +1100
Subject: [PATCH 43/56] Remove DefinitelyTyped reference in CONTRIBUTING.md

---
 CONTRIBUTING.md | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 8924985f..24384b04 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -27,11 +27,6 @@ select the added contribution type.
 Please make sure to run the tests before you commit your changes. You can do so by running
 `npm test`.
 
-### Update Typings
-
-The TypeScript type definitions can be found in the
-[DefinitelyTyped repo](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/testing-library__react-hooks).
-
 ## Help needed
 
 Please check out the

From 78c146e4662de1ae166a4a700e3961ab8067c7fb Mon Sep 17 00:00:00 2001
From: marcosvega91 <marcomoretti0103@gmail.com>
Date: Mon, 14 Dec 2020 12:58:29 +0100
Subject: [PATCH 44/56] chore: disable declaration for tests

---
 .eslintrc          | 5 ++++-
 package.json       | 1 +
 test/tsconfig.json | 8 ++++++++
 tsconfig.json      | 5 ++---
 4 files changed, 15 insertions(+), 4 deletions(-)
 create mode 100644 test/tsconfig.json

diff --git a/.eslintrc b/.eslintrc
index d80c5b77..61a9e0e3 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -1,5 +1,5 @@
 {
-  "extends":[ "./node_modules/kcd-scripts/eslint.js"],
+  "extends": ["./node_modules/kcd-scripts/eslint.js"],
   "rules": {
     "max-lines-per-function": "off",
     "no-constant-condition": "off",
@@ -7,5 +7,8 @@
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
     "import/no-unresolved": "off"
+  },
+  "parserOptions": {
+    "project": ["./tsconfig.json", "./test/tsconfig.json"]
   }
 }
diff --git a/package.json b/package.json
index 6cc8d613..3c04f860 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,7 @@
   "version": "0.0.0-semantically-released",
   "description": "Simple and complete React hooks testing utilities that encourage good testing practices.",
   "main": "lib/index.js",
+  "types": "lib/index.d.ts",
   "keywords": [
     "testing",
     "react",
diff --git a/test/tsconfig.json b/test/tsconfig.json
new file mode 100644
index 00000000..48209b56
--- /dev/null
+++ b/test/tsconfig.json
@@ -0,0 +1,8 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "declaration": false
+  },
+  "exclude": [],
+  "include": ["."]
+}
diff --git a/tsconfig.json b/tsconfig.json
index 81cc29e6..1337ac30 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,9 +1,8 @@
 {
-  
   "extends": "./node_modules/kcd-scripts/shared-tsconfig.json",
   "compilerOptions": {
     "allowJs": true,
-    "target": "ES6",
+    "target": "ES6"
   },
-  "include": ["./test"]
+  "exclude": ["./test"]
 }

From 9d957ba9a42c103c34b1c2e5173dc4043f8ba4a6 Mon Sep 17 00:00:00 2001
From: Juhana Jauhiainen <juhana.jauhiainen@gmail.com>
Date: Mon, 14 Dec 2020 18:18:07 +0200
Subject: [PATCH 45/56] Removes createTimeoutError. Adds constructor to
 TimeoutError. Adds typeing to waitForValueToChange options

---
 src/asyncUtils.ts | 21 +++++++++------------
 1 file changed, 9 insertions(+), 12 deletions(-)

diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index a7732d11..068480ed 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -7,12 +7,9 @@ export interface WaitOptions {
 }
 
 class TimeoutError extends Error {
-  timeout = true
-}
-
-function createTimeoutError(utilName: string, { timeout }: Pick<WaitOptions, 'timeout'>) {
-  const timeoutError = new TimeoutError(`Timed out in ${utilName} after ${timeout as number}ms.`)
-  return timeoutError
+  constructor(utilName: string, { timeout }: Pick<WaitOptions, 'timeout'>) {
+    super(`Timed out in ${utilName} after ${timeout as number}ms.`)
+  }
 }
 
 function resolveAfter(ms: number) {
@@ -27,10 +24,10 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
   const waitForNextUpdate = async (options: Pick<WaitOptions, 'timeout'> = {}) => {
     if (!nextUpdatePromise) {
       nextUpdatePromise = new Promise((resolve, reject) => {
-        let timeoutId: number
+        let timeoutId: ReturnType<typeof setTimeout>
         if (options.timeout && options.timeout > 0) {
-          timeoutId = window.setTimeout(
-            () => reject(createTimeoutError('waitForNextUpdate', options)),
+          timeoutId = setTimeout(
+            () => reject(new TimeoutError('waitForNextUpdate', options)),
             options.timeout
           )
         }
@@ -78,7 +75,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
           }
         } catch (error: unknown) {
           if (error instanceof TimeoutError) {
-            throw createTimeoutError('waitFor', { timeout: initialTimeout })
+            throw new TimeoutError('waitFor', { timeout: initialTimeout })
           }
           throw error as Error
         }
@@ -91,7 +88,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
     }
   }
 
-  const waitForValueToChange = async (selector: () => unknown, options = {}) => {
+  const waitForValueToChange = async (selector: () => unknown, options: WaitOptions = {}) => {
     const initialValue = selector()
     try {
       await waitFor(() => selector() !== initialValue, {
@@ -100,7 +97,7 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
       })
     } catch (error: unknown) {
       if (error instanceof TimeoutError) {
-        throw createTimeoutError('waitForValueToChange', options)
+        throw new TimeoutError('waitForValueToChange', options)
       }
       throw error as Error
     }

From d1c36bda66aa3bb0e1adb289c4422f158b1bfafc Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:01:19 +1100
Subject: [PATCH 46/56] Remove conditional in TestHook for hookProps

---
 src/pure.tsx | 8 ++------
 1 file changed, 2 insertions(+), 6 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index e54c0f72..d2fff53f 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -16,12 +16,8 @@ function TestHook<TProps, TResult>({
   children
 }: TestHookProps<TProps, TResult>) {
   try {
-    if (hookProps) {
-      children(callback(hookProps))
-    } else {
-      // coerce into undefined, so it maintains the previous behaviour
-      children(callback((undefined as unknown) as TProps))
-    }
+    // coerce undefined into TProps, so it maintains the previous behaviour
+    children(callback(hookProps as TProps))
     // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
   } catch (err) {
     // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access

From 21a1c6e67d8bd6746f43590a715725f9e69e9b32 Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:05:08 +1100
Subject: [PATCH 47/56] Replace old types defs with referenced types in
 dependencies

---
 package.json | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/package.json b/package.json
index 3c04f860..572dd51b 100644
--- a/package.json
+++ b/package.json
@@ -38,7 +38,8 @@
   },
   "dependencies": {
     "@babel/runtime": "^7.12.5",
-    "@types/testing-library__react-hooks": "^3.4.0"
+    "@types/react": ">=16.9.0",
+    "@types/react-test-renderer": ">=16.9.0"
   },
   "devDependencies": {
     "@typescript-eslint/eslint-plugin": "^4.9.1",

From d621cda95bdd2c08d091ae7d29339f722a21c5fc Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:06:18 +1100
Subject: [PATCH 48/56] Remove destructuring of `testRenderer`

---
 src/pure.tsx | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index d2fff53f..f1860e18 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -89,19 +89,17 @@ function renderHook<TProps, TResult>(
       </Suspense>
     ) as ReactElement
 
-  let testRenderer: ReactTestRenderer | undefined
+  let testRenderer: ReactTestRenderer
   // eslint-disable-next-line @typescript-eslint/no-floating-promises
   act(() => {
     testRenderer = create(toRender())
   })
-  // eslint-disable-next-line @typescript-eslint/unbound-method
-  const { unmount, update } = testRenderer as ReactTestRenderer
-
+  
   function rerenderHook(newProps: typeof initialProps = hookProps.current) {
     hookProps.current = newProps
     // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
-      update(toRender())
+      testRenderer.update(toRender())
     })
   }
 
@@ -109,7 +107,7 @@ function renderHook<TProps, TResult>(
     // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
       removeCleanup(unmountHook)
-      unmount()
+      testRenderer.unmount()
     })
   }
 

From 900e89c1ac3fd82998c55abeb2fb75f99818cb7d Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:13:38 +1100
Subject: [PATCH 49/56] Disabled floating promise lint rule globally

---
 .eslintrc    | 3 ++-
 src/pure.tsx | 5 +----
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index 61a9e0e3..b725c9e7 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -6,7 +6,8 @@
     "no-await-in-loop": "off",
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
-    "import/no-unresolved": "off"
+    "import/no-unresolved": "off",
+    "@typescript-eslint/no-floating-promises": "off"
   },
   "parserOptions": {
     "project": ["./tsconfig.json", "./test/tsconfig.json"]
diff --git a/src/pure.tsx b/src/pure.tsx
index f1860e18..7a8b1b4b 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -90,21 +90,18 @@ function renderHook<TProps, TResult>(
     ) as ReactElement
 
   let testRenderer: ReactTestRenderer
-  // eslint-disable-next-line @typescript-eslint/no-floating-promises
   act(() => {
     testRenderer = create(toRender())
   })
-  
+
   function rerenderHook(newProps: typeof initialProps = hookProps.current) {
     hookProps.current = newProps
-    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
       testRenderer.update(toRender())
     })
   }
 
   function unmountHook() {
-    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => {
       removeCleanup(unmountHook)
       testRenderer.unmount()

From 4ead36f7e3fdfd2347b3441274880039ce0102d9 Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:16:30 +1100
Subject: [PATCH 50/56] Refactor TestHook catch to not disable lint rules

---
 src/pure.tsx | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index 7a8b1b4b..2dbc91d0 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -3,12 +3,17 @@ import { act, create, ReactTestRenderer } from 'react-test-renderer'
 import asyncUtils from './asyncUtils'
 import { cleanup, addCleanup, removeCleanup } from './cleanup'
 
+function isPromise<T>(value: unknown): boolean {
+  return typeof (value as PromiseLike<T>).then === 'function'
+}
+
 type TestHookProps<TProps, TResult> = {
   callback: (props: TProps) => TResult
   hookProps: TProps | undefined
   onError: (error: Error) => void
   children: (value: TResult) => void
 }
+
 function TestHook<TProps, TResult>({
   callback,
   hookProps,
@@ -18,13 +23,11 @@ function TestHook<TProps, TResult>({
   try {
     // coerce undefined into TProps, so it maintains the previous behaviour
     children(callback(hookProps as TProps))
-    // eslint-disable-next-line @typescript-eslint/no-implicit-any-catch
-  } catch (err) {
-    // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
-    if (err.then) {
+  } catch (err: unknown) {
+    if (isPromise(err)) {
       throw err
     } else {
-      onError(err)
+      onError(err as Error)
     }
   }
   return null

From 25509bab27a0f15bb88a623b4a034c3d7452401a Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:23:19 +1100
Subject: [PATCH 51/56] Disabled eslint error for while(true)

---
 .eslintrc         | 3 ++-
 src/asyncUtils.ts | 1 -
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index b725c9e7..6b483ba4 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -7,7 +7,8 @@
     "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
     "import/no-unresolved": "off",
-    "@typescript-eslint/no-floating-promises": "off"
+    "@typescript-eslint/no-floating-promises": "off",
+    "@typescript-eslint/no-unnecessary-condition": ["error", { "allowConstantLoopConditions": true }]
   },
   "parserOptions": {
     "project": ["./tsconfig.json", "./test/tsconfig.json"]
diff --git a/src/asyncUtils.ts b/src/asyncUtils.ts
index 068480ed..22921721 100644
--- a/src/asyncUtils.ts
+++ b/src/asyncUtils.ts
@@ -60,7 +60,6 @@ function asyncUtils(addResolver: (callback: () => void) => void) {
 
     const waitForResult = async () => {
       const initialTimeout = timeout
-      // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
       while (true) {
         const startTime = Date.now()
         try {

From db8a6f30c6a8e85a46b9276118080390960985af Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:35:54 +1100
Subject: [PATCH 52/56] Cleaned up some line warnings from tests

---
 test/customHook.ts   | 1 -
 test/suspenseHook.ts | 3 +--
 test/useReducer.ts   | 1 -
 test/useState.ts     | 6 ++----
 4 files changed, 3 insertions(+), 8 deletions(-)

diff --git a/test/customHook.ts b/test/customHook.ts
index 4875efee..871c5619 100644
--- a/test/customHook.ts
+++ b/test/customHook.ts
@@ -1,4 +1,3 @@
-/* eslint-disable @typescript-eslint/no-floating-promises */
 import { useState, useCallback } from 'react'
 import { renderHook, act } from '../src'
 
diff --git a/test/suspenseHook.ts b/test/suspenseHook.ts
index c4aef046..8d696927 100644
--- a/test/suspenseHook.ts
+++ b/test/suspenseHook.ts
@@ -22,8 +22,7 @@ describe('suspense hook tests', () => {
   const useFetchName = (isSuccessful = true) => {
     const name = fetchName(isSuccessful)
     if (name instanceof Promise || name instanceof Error) {
-      // eslint-disable-next-line @typescript-eslint/no-throw-literal
-      throw name
+      throw name as unknown
     }
     return name
   }
diff --git a/test/useReducer.ts b/test/useReducer.ts
index 43add078..7b98431a 100644
--- a/test/useReducer.ts
+++ b/test/useReducer.ts
@@ -11,7 +11,6 @@ describe('useReducer tests', () => {
 
     expect(initialState).toBe(0)
 
-    // eslint-disable-next-line @typescript-eslint/no-floating-promises
     act(() => dispatch({ type: 'inc' }))
 
     const [state] = result.current
diff --git a/test/useState.ts b/test/useState.ts
index fe7726cf..42f3f8b0 100644
--- a/test/useState.ts
+++ b/test/useState.ts
@@ -5,7 +5,7 @@ describe('useState tests', () => {
   test('should use setState value', () => {
     const { result } = renderHook(() => useState('foo'))
 
-    const [value] = result.current 
+    const [value] = result.current
 
     expect(value).toBe('foo')
   })
@@ -13,11 +13,9 @@ describe('useState tests', () => {
   test('should update setState value using setter', () => {
     const { result } = renderHook(() => useState('foo'))
 
-
     const [ignoredValue, setValue] = result.current
 
-    // eslint-disable-next-line @typescript-eslint/no-floating-promises
-    act(() => setValue('bar')) 
+    act(() => setValue('bar'))
 
     const [value] = result.current
 

From f0d080e309fe4c1d41cd0827ab5f3cf008d12be0 Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:49:48 +1100
Subject: [PATCH 53/56] Added "typecheck" kcd-script to improve "validate"
 script

---
 .eslintrc    | 4 ++--
 package.json | 3 ++-
 2 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index 6b483ba4..052c9caa 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -4,11 +4,11 @@
     "max-lines-per-function": "off",
     "no-constant-condition": "off",
     "no-await-in-loop": "off",
-    "react-hooks/rules-of-hooks": "off",
     "no-console": "off",
     "import/no-unresolved": "off",
+    "react-hooks/rules-of-hooks": "off",
     "@typescript-eslint/no-floating-promises": "off",
-    "@typescript-eslint/no-unnecessary-condition": ["error", { "allowConstantLoopConditions": true }]
+    "@typescript-eslint/no-unnecessary-condition": "off"
   },
   "parserOptions": {
     "project": ["./tsconfig.json", "./test/tsconfig.json"]
diff --git a/package.json b/package.json
index 572dd51b..5e90940a 100644
--- a/package.json
+++ b/package.json
@@ -28,10 +28,11 @@
     "validate": "kcd-scripts validate",
     "prepare": "npm run build",
     "build": "kcd-scripts build --out-dir lib",
+    "test": "kcd-scripts test",
+    "typecheck": "kcd-scripts typecheck",
     "lint": "kcd-scripts lint",
     "format": "kcd-scripts format",
     "coverage": "codecov",
-    "test": "kcd-scripts test",
     "docs:dev": "docz dev",
     "docs:build": "docz build",
     "contributors:add": "all-contributors add"

From 84a40add0d1713d4a44deaec5e2ecbcf3e256663 Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 13:55:00 +1100
Subject: [PATCH 54/56] Clean up ThrowError type in errorHook tests

---
 test/errorHook.ts | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/test/errorHook.ts b/test/errorHook.ts
index 811c1b7b..e507bb92 100644
--- a/test/errorHook.ts
+++ b/test/errorHook.ts
@@ -1,17 +1,16 @@
 import { useState, useEffect } from 'react'
 import { renderHook } from '../src'
 
-type throwError = Error | boolean | undefined
 describe('error hook tests', () => {
-  function useError(throwError: throwError) {
+  function useError(throwError: boolean) {
     if (throwError) {
       throw new Error('expected')
     }
     return true
   }
 
-  function useAsyncError(throwError: throwError) {
-    const [value, setValue] = useState<throwError>()
+  function useAsyncError(throwError: boolean) {
+    const [value, setValue] = useState<boolean>()
     useEffect(() => {
       const timeout = setTimeout(() => setValue(throwError), 100)
       return () => clearTimeout(timeout)
@@ -19,7 +18,7 @@ describe('error hook tests', () => {
     return useError(value)
   }
 
-  function useEffectError(throwError: throwError) {
+  function useEffectError(throwError: boolean) {
     useEffect(() => {
       useError(throwError)
     }, [throwError])

From f33e4576aacf66ee31cbd817fd29a19789d7190b Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 14:12:19 +1100
Subject: [PATCH 55/56] Replace VoidFunction with () => void

---
 src/pure.tsx | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/pure.tsx b/src/pure.tsx
index 2dbc91d0..a1c14897 100644
--- a/src/pure.tsx
+++ b/src/pure.tsx
@@ -39,7 +39,7 @@ function Fallback() {
 
 function resultContainer<TValue>() {
   const results: Array<{ value?: TValue; error?: Error }> = []
-  const resolvers: Array<VoidFunction> = []
+  const resolvers: Array<() => void> = []
 
   const result = {
     get all() {
@@ -65,7 +65,7 @@ function resultContainer<TValue>() {
 
   return {
     result,
-    addResolver: (resolver: VoidFunction) => {
+    addResolver: (resolver: () => void) => {
       resolvers.push(resolver)
     },
     setValue: (value: TValue) => updateResult(value),

From a5754f2f65cb6ee17f5d7f27b1f9f153ddd16ed6 Mon Sep 17 00:00:00 2001
From: Michael Peyper <mpeyper7@gmail.com>
Date: Tue, 15 Dec 2020 14:15:31 +1100
Subject: [PATCH 56/56] Replace CallableFunction with a more explicit function
 type

---
 test/useRef.ts | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/useRef.ts b/test/useRef.ts
index 6434d77d..9d3851ff 100644
--- a/test/useRef.ts
+++ b/test/useRef.ts
@@ -13,7 +13,7 @@ describe('useHook tests', () => {
 
   test('should handle useImperativeHandle hook', () => {
     const { result } = renderHook(() => {
-      const ref = useRef<Record<string, CallableFunction>>({})
+      const ref = useRef<Record<string, () => boolean>>({})
       useImperativeHandle(ref, () => ({
         fakeImperativeMethod: () => true
       }))