diff --git a/README.md b/README.md
index b24c136e..d42d601f 100644
--- a/README.md
+++ b/README.md
@@ -267,6 +267,7 @@ Thanks goes to these people ([emoji key][emojis]):
 
 <!-- markdownlint-enable -->
 <!-- prettier-ignore-end -->
+
 <!-- ALL-CONTRIBUTORS-LIST:END -->
 
 This project follows the [all-contributors][all-contributors] specification.
diff --git a/package.json b/package.json
index e41e26bb..8858bf60 100644
--- a/package.json
+++ b/package.json
@@ -24,14 +24,16 @@
     "node": ">=10"
   },
   "scripts": {
-    "build": "kcd-scripts build --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --bundle --no-clean",
+    "build": "npm run build:bundles ; npm run build:types",
+    "build:bundles": "kcd-scripts build --ignore \"**/__tests__/**,**/__node_tests__/**,**/__mocks__/**\" && kcd-scripts build --bundle --no-clean",
+    "build:types": "tsc --build tsconfig.build.json",
     "lint": "kcd-scripts lint",
     "setup": "npm install && npm run validate -s",
     "test": "kcd-scripts test",
     "test:debug": "node --inspect-brk ./node_modules/.bin/jest --watch --runInBand",
     "test:update": "npm test -- --updateSnapshot --coverage",
     "validate": "kcd-scripts validate",
-    "typecheck": "dtslint ./types/"
+    "typecheck-DISABLED": "dtslint ./types/"
   },
   "files": [
     "dist",
@@ -41,16 +43,18 @@
     "@babel/runtime": "^7.10.2",
     "aria-query": "^4.0.2",
     "dom-accessibility-api": "^0.4.5",
+    "eslint-import-resolver-typescript": "^2.0.0",
     "pretty-format": "^25.5.0"
   },
   "devDependencies": {
-    "dtslint": "^3.6.9",
     "@testing-library/jest-dom": "^5.9.0",
+    "dtslint": "^3.6.11",
     "jest-in-case": "^1.0.2",
     "jest-serializer-ansi": "^1.0.3",
     "jest-watch-select-projects": "^2.0.0",
     "jsdom": "^16.2.2",
-    "kcd-scripts": "^6.2.0"
+    "kcd-scripts": "^6.2.3",
+    "typescript": "^3.9.5"
   },
   "eslintConfig": {
     "extends": "./node_modules/kcd-scripts/eslint.js",
@@ -59,6 +63,11 @@
       "import/no-unassigned-import": "off",
       "import/no-useless-path-segments": "off",
       "no-console": "off"
+    },
+    "settings": {
+      "import/resolver": {
+        "typescript": {}
+      }
     }
   },
   "eslintIgnore": [
diff --git a/src/__tests__/events.js b/src/__tests__/events.js
index f2f8d2a9..37b62c10 100644
--- a/src/__tests__/events.js
+++ b/src/__tests__/events.js
@@ -140,17 +140,21 @@ const eventTypes = [
 
 const allEvents = Object.keys(eventMap)
 
-const bubblingEvents = allEvents
-  .filter(eventName => eventMap[eventName].defaultInit.bubbles)
+const bubblingEvents = allEvents.filter(
+  eventName => eventMap[eventName].defaultInit.bubbles,
+)
 
-const composedEvents = allEvents
-  .filter(eventName => eventMap[eventName].defaultInit.composed)
+const composedEvents = allEvents.filter(
+  eventName => eventMap[eventName].defaultInit.composed,
+)
 
-const nonBubblingEvents = allEvents
-  .filter(eventName => !bubblingEvents.includes(eventName))
+const nonBubblingEvents = allEvents.filter(
+  eventName => !bubblingEvents.includes(eventName),
+)
 
-const nonComposedEvents = allEvents
-  .filter(eventName => !composedEvents.includes(eventName))
+const nonComposedEvents = allEvents.filter(
+  eventName => !composedEvents.includes(eventName),
+)
 
 eventTypes.forEach(({type, events, elementType}) => {
   describe(`${type} Events`, () => {
@@ -203,7 +207,7 @@ describe(`Composed Events`, () => {
       const spy = jest.fn()
       node.addEventListener(event.toLowerCase(), spy)
 
-      const shadowRoot = node.attachShadow({ mode: 'closed' })
+      const shadowRoot = node.attachShadow({mode: 'closed'})
       const innerNode = document.createElement('div')
       shadowRoot.appendChild(innerNode)
 
@@ -218,7 +222,7 @@ describe(`Composed Events`, () => {
       const spy = jest.fn()
       node.addEventListener(event.toLowerCase(), spy)
 
-      const shadowRoot = node.attachShadow({ mode: 'closed' })
+      const shadowRoot = node.attachShadow({mode: 'closed'})
       const innerNode = document.createElement('div')
       shadowRoot.appendChild(innerNode)
 
@@ -234,7 +238,7 @@ describe(`Aliased Events`, () => {
       const node = document.createElement('div')
       const spy = jest.fn()
       node.addEventListener(eventAliasMap[eventAlias].toLowerCase(), spy)
-      
+
       fireEvent[eventAlias](node)
       expect(spy).toHaveBeenCalledTimes(1)
     })
diff --git a/src/__tests__/role.js b/src/__tests__/role.js
index a187a77b..7e3164ba 100644
--- a/src/__tests__/role.js
+++ b/src/__tests__/role.js
@@ -346,7 +346,9 @@ Here are the accessible roles:
 test('has no useful error message in findBy', async () => {
   const {findByRole} = render(`<li />`)
 
-  await expect(findByRole('option', {timeout: 1})).rejects.toThrow('Unable to find role="option"')
+  await expect(findByRole('option', {timeout: 1})).rejects.toThrow(
+    'Unable to find role="option"',
+  )
 })
 
 test('explicit role is most specific', () => {
diff --git a/src/config.js b/src/config.ts
similarity index 76%
rename from src/config.js
rename to src/config.ts
index 44b51146..f012b8a4 100644
--- a/src/config.js
+++ b/src/config.ts
@@ -1,9 +1,24 @@
 import {prettyDOM} from './pretty-dom'
 
+export interface Config {
+  testIdAttribute: string
+  asyncWrapper(cb: (...args: any[]) => any): Promise<any>
+  eventWrapper(cb: (...args: any[]) => any): void
+  getElementError: (message: string, container: Element) => Error
+  asyncUtilTimeout: number
+  defaultHidden: boolean
+  showOriginalStackTrace: boolean
+  throwSuggestions: boolean
+}
+
+interface InternalConfig {
+  _disableExpensiveErrorDiagnostics: boolean
+}
+
 // It would be cleaner for this to live inside './queries', but
 // other parts of the code assume that all exports from
 // './queries' are query functions.
-let config = {
+let config: Config & InternalConfig = {
   testIdAttribute: 'data-testid',
   asyncUtilTimeout: 1000,
   // this is to support React's async `act` function.
@@ -44,7 +59,11 @@ export function runWithExpensiveErrorDiagnosticsDisabled(callback) {
   }
 }
 
-export function configure(newConfig) {
+export interface ConfigFn {
+  (existingConfig: Config): Partial<Config>
+}
+
+export function configure(newConfig: Partial<Config> | ConfigFn): void {
   if (typeof newConfig === 'function') {
     // Pass the existing config out to the provided function
     // and accept a delta in return
diff --git a/src/event-map.js b/src/event-map.js
deleted file mode 100644
index 98d78e66..00000000
--- a/src/event-map.js
+++ /dev/null
@@ -1,350 +0,0 @@
-export const eventMap = {
-    // Clipboard Events
-    copy: {
-      EventType: 'ClipboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    cut: {
-      EventType: 'ClipboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    paste: {
-      EventType: 'ClipboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    // Composition Events
-    compositionEnd: {
-      EventType: 'CompositionEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    compositionStart: {
-      EventType: 'CompositionEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    compositionUpdate: {
-      EventType: 'CompositionEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    // Keyboard Events
-    keyDown: {
-      EventType: 'KeyboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
-    },
-    keyPress: {
-      EventType: 'KeyboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
-    },
-    keyUp: {
-      EventType: 'KeyboardEvent',
-      defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
-    },
-    // Focus Events
-    focus: {
-      EventType: 'FocusEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    blur: {
-      EventType: 'FocusEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    focusIn: {
-      EventType: 'FocusEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    focusOut: {
-      EventType: 'FocusEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    // Form Events
-    change: {
-      EventType: 'Event',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-    input: {
-      EventType: 'InputEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    invalid: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: true},
-    },
-    submit: {
-      EventType: 'Event',
-      defaultInit: {bubbles: true, cancelable: true},
-    },
-    reset: {
-      EventType: 'Event',
-      defaultInit: {bubbles: true, cancelable: true},
-    },
-    // Mouse Events
-    click: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, button: 0, composed: true},
-    },
-    contextMenu: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    dblClick: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    drag: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    dragEnd: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    dragEnter: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    dragExit: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    dragLeave: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    dragOver: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    dragStart: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    drop: {
-      EventType: 'DragEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    mouseDown: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    mouseEnter: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    mouseLeave: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    mouseMove: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    mouseOut: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    mouseOver: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    mouseUp: {
-      EventType: 'MouseEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    // Selection Events
-    select: {
-      EventType: 'Event',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-    // Touch Events
-    touchCancel: {
-      EventType: 'TouchEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    touchEnd: {
-      EventType: 'TouchEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    touchMove: {
-      EventType: 'TouchEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    touchStart: {
-      EventType: 'TouchEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    // UI Events
-    scroll: {
-      EventType: 'UIEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    // Wheel Events
-    wheel: {
-      EventType: 'WheelEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    // Media Events
-    abort: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    canPlay: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    canPlayThrough: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    durationChange: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    emptied: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    encrypted: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    ended: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    loadedData: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    loadedMetadata: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    loadStart: {
-      EventType: 'ProgressEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    pause: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    play: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    playing: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    progress: {
-      EventType: 'ProgressEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    rateChange: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    seeked: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    seeking: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    stalled: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    suspend: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    timeUpdate: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    volumeChange: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    waiting: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    // Image Events
-    load: {
-      EventType: 'UIEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    error: {
-      EventType: 'Event',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    // Animation Events
-    animationStart: {
-      EventType: 'AnimationEvent',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-    animationEnd: {
-      EventType: 'AnimationEvent',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-    animationIteration: {
-      EventType: 'AnimationEvent',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-    // Transition Events
-    transitionEnd: {
-      EventType: 'TransitionEvent',
-      defaultInit: {bubbles: true, cancelable: true},
-    },
-    // pointer events
-    pointerOver: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    pointerEnter: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    pointerDown: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    pointerMove: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    pointerUp: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    pointerCancel: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: false, composed: true},
-    },
-    pointerOut: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: true, cancelable: true, composed: true},
-    },
-    pointerLeave: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: false, cancelable: false},
-    },
-    gotPointerCapture: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    lostPointerCapture: {
-      EventType: 'PointerEvent',
-      defaultInit: {bubbles: false, cancelable: false, composed: true},
-    },
-    // history events
-    popState: {
-      EventType: 'PopStateEvent',
-      defaultInit: {bubbles: true, cancelable: false},
-    },
-  }
-  
-  export const eventAliasMap = {
-    doubleClick: 'dblClick',
-  }
diff --git a/src/event-map.ts b/src/event-map.ts
new file mode 100644
index 00000000..29348eb1
--- /dev/null
+++ b/src/event-map.ts
@@ -0,0 +1,460 @@
+export type EventMapKey =
+  | 'copy'
+  | 'cut'
+  | 'paste'
+  | 'compositionEnd'
+  | 'compositionStart'
+  | 'compositionUpdate'
+  | 'keyDown'
+  | 'keyPress'
+  | 'keyUp'
+  | 'focus'
+  | 'blur'
+  | 'focusIn'
+  | 'focusOut'
+  | 'change'
+  | 'input'
+  | 'invalid'
+  | 'submit'
+  | 'reset'
+  | 'click'
+  | 'contextMenu'
+  | 'dblClick'
+  | 'drag'
+  | 'dragEnd'
+  | 'dragEnter'
+  | 'dragExit'
+  | 'dragLeave'
+  | 'dragOver'
+  | 'dragStart'
+  | 'drop'
+  | 'mouseDown'
+  | 'mouseEnter'
+  | 'mouseLeave'
+  | 'mouseMove'
+  | 'mouseOut'
+  | 'mouseOver'
+  | 'mouseUp'
+  | 'popState'
+  | 'select'
+  | 'touchCancel'
+  | 'touchEnd'
+  | 'touchMove'
+  | 'touchStart'
+  | 'scroll'
+  | 'wheel'
+  | 'abort'
+  | 'canPlay'
+  | 'canPlayThrough'
+  | 'durationChange'
+  | 'emptied'
+  | 'encrypted'
+  | 'ended'
+  | 'loadedData'
+  | 'loadedMetadata'
+  | 'loadStart'
+  | 'pause'
+  | 'play'
+  | 'playing'
+  | 'progress'
+  | 'rateChange'
+  | 'seeked'
+  | 'seeking'
+  | 'stalled'
+  | 'suspend'
+  | 'timeUpdate'
+  | 'volumeChange'
+  | 'waiting'
+  | 'load'
+  | 'error'
+  | 'animationStart'
+  | 'animationEnd'
+  | 'animationIteration'
+  | 'transitionEnd'
+  | 'pointerOver'
+  | 'pointerEnter'
+  | 'pointerDown'
+  | 'pointerMove'
+  | 'pointerUp'
+  | 'pointerCancel'
+  | 'pointerOut'
+  | 'pointerLeave'
+  | 'gotPointerCapture'
+  | 'lostPointerCapture'
+
+type LegacyKeyboardEventInit = {
+  // lib.dom.ts marks 'charCode' as deprecated in KeyboardEvent and does not include it in KeyboardEventInit
+  charCode?: number
+} & KeyboardEventInit
+
+type EventMapValue =
+  | {EventType: 'AnimationEvent'; defaultInit: AnimationEventInit}
+  | {EventType: 'ClipboardEvent'; defaultInit: ClipboardEventInit}
+  | {EventType: 'CompositionEvent'; defaultInit: CompositionEventInit}
+  | {EventType: 'DragEvent'; defaultInit: DragEventInit}
+  | {EventType: 'Event'; defaultInit: EventInit}
+  | {EventType: 'FocusEvent'; defaultInit: FocusEventInit}
+  | {EventType: 'KeyboardEvent'; defaultInit: LegacyKeyboardEventInit}
+  | {EventType: 'InputEvent'; defaultInit: InputEventInit}
+  | {EventType: 'MouseEvent'; defaultInit: MouseEventInit}
+  | {EventType: 'PointerEvent'; defaultInit: PointerEventInit}
+  | {EventType: 'PopStateEvent'; defaultInit: PopStateEventInit}
+  | {EventType: 'ProgressEvent'; defaultInit: ProgressEventInit}
+  | {EventType: 'TouchEvent'; defaultInit: TouchEventInit}
+  | {EventType: 'TransitionEvent'; defaultInit: TransitionEventInit}
+  | {EventType: 'UIEvent'; defaultInit: UIEventInit}
+  | {EventType: 'WheelEvent'; defaultInit: WheelEventInit}
+
+export const eventMap: Record<EventMapKey, EventMapValue> = {
+  // Clipboard Events
+  copy: {
+    EventType: 'ClipboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  cut: {
+    EventType: 'ClipboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  paste: {
+    EventType: 'ClipboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  // Composition Events
+  compositionEnd: {
+    EventType: 'CompositionEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  compositionStart: {
+    EventType: 'CompositionEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  compositionUpdate: {
+    EventType: 'CompositionEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  // Keyboard Events
+  keyDown: {
+    EventType: 'KeyboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
+  },
+  keyPress: {
+    EventType: 'KeyboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
+  },
+  keyUp: {
+    EventType: 'KeyboardEvent',
+    defaultInit: {bubbles: true, cancelable: true, charCode: 0, composed: true},
+  },
+  // Focus Events
+  focus: {
+    EventType: 'FocusEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  blur: {
+    EventType: 'FocusEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  focusIn: {
+    EventType: 'FocusEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  focusOut: {
+    EventType: 'FocusEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  // Form Events
+  change: {
+    EventType: 'Event',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+  input: {
+    EventType: 'InputEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  invalid: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: true},
+  },
+  submit: {
+    EventType: 'Event',
+    defaultInit: {bubbles: true, cancelable: true},
+  },
+  reset: {
+    EventType: 'Event',
+    defaultInit: {bubbles: true, cancelable: true},
+  },
+  // Mouse Events
+  click: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, button: 0, composed: true},
+  },
+  contextMenu: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  dblClick: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  drag: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  dragEnd: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  dragEnter: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  dragExit: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  dragLeave: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  dragOver: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  dragStart: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  drop: {
+    EventType: 'DragEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  mouseDown: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  mouseEnter: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  mouseLeave: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  mouseMove: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  mouseOut: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  mouseOver: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  mouseUp: {
+    EventType: 'MouseEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  // Selection Events
+  select: {
+    EventType: 'Event',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+  // Touch Events
+  touchCancel: {
+    EventType: 'TouchEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  touchEnd: {
+    EventType: 'TouchEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  touchMove: {
+    EventType: 'TouchEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  touchStart: {
+    EventType: 'TouchEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  // UI Events
+  scroll: {
+    EventType: 'UIEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  // Wheel Events
+  wheel: {
+    EventType: 'WheelEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  // Media Events
+  abort: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  canPlay: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  canPlayThrough: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  durationChange: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  emptied: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  encrypted: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  ended: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  loadedData: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  loadedMetadata: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  loadStart: {
+    EventType: 'ProgressEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  pause: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  play: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  playing: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  progress: {
+    EventType: 'ProgressEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  rateChange: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  seeked: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  seeking: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  stalled: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  suspend: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  timeUpdate: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  volumeChange: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  waiting: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  // Image Events
+  load: {
+    EventType: 'UIEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  error: {
+    EventType: 'Event',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  // Animation Events
+  animationStart: {
+    EventType: 'AnimationEvent',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+  animationEnd: {
+    EventType: 'AnimationEvent',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+  animationIteration: {
+    EventType: 'AnimationEvent',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+  // Transition Events
+  transitionEnd: {
+    EventType: 'TransitionEvent',
+    defaultInit: {bubbles: true, cancelable: true},
+  },
+  // pointer events
+  pointerOver: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  pointerEnter: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  pointerDown: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  pointerMove: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  pointerUp: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  pointerCancel: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: false, composed: true},
+  },
+  pointerOut: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: true, cancelable: true, composed: true},
+  },
+  pointerLeave: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: false, cancelable: false},
+  },
+  gotPointerCapture: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  lostPointerCapture: {
+    EventType: 'PointerEvent',
+    defaultInit: {bubbles: false, cancelable: false, composed: true},
+  },
+  // history events
+  popState: {
+    EventType: 'PopStateEvent',
+    defaultInit: {bubbles: true, cancelable: false},
+  },
+}
+
+type EventAliasMapKey = 'doubleClick'
+export const eventAliasMap: Record<EventAliasMapKey, EventMapKey> = {
+  doubleClick: 'dblClick',
+}
+
+export type EventType = EventMapKey | EventAliasMapKey
diff --git a/src/events.js b/src/events.ts
similarity index 66%
rename from src/events.js
rename to src/events.ts
index 6d19c1fa..d50fd7ab 100644
--- a/src/events.js
+++ b/src/events.ts
@@ -1,8 +1,16 @@
 import {getConfig} from './config'
 import {getWindowFromNode} from './helpers'
-import {eventMap, eventAliasMap} from './event-map'
+import {eventMap, EventMapKey, eventAliasMap, EventType} from './event-map'
 
-function fireEvent(element, event) {
+declare global {
+  // FIXME we should not augment the interface here
+  interface Window {
+    DataTransfer: () => void
+    Event: () => void
+  }
+}
+
+function internalfireEvent(element: EventTarget, event: Event) {
   return getConfig().eventWrapper(() => {
     if (!event) {
       throw new Error(
@@ -18,9 +26,26 @@ function fireEvent(element, event) {
   })
 }
 
-const createEvent = {}
+function isDragEventInit(eventInit: unknown): eventInit is DragEventInit {
+  return typeof (eventInit as DragEventInit).dataTransfer === 'object'
+}
+
+type EventTargetWithFiles = HTMLInputElement
+type EventTargetWithValue =
+  | HTMLInputElement
+  | HTMLButtonElement
+  | HTMLOutputElement
+
+type CreateObject = {
+  [K in EventType]: (
+    //element: Document | Element | Window | Node,
+    element: EventTarget,
+    options?: {},
+  ) => Event
+}
+const createEvent = {} as CreateObject
 
-Object.keys(eventMap).forEach(key => {
+Object.keys(eventMap).forEach((key: EventMapKey) => {
   const {EventType, defaultInit} = eventMap[key]
   const eventName = key.toLowerCase()
 
@@ -30,8 +55,11 @@ Object.keys(eventMap).forEach(key => {
         `Unable to fire a "${key}" event - please provide a DOM element.`,
       )
     }
-    const eventInit = {...defaultInit, ...init}
-    const {target: {value, files, ...targetProperties} = {}} = eventInit
+    const eventInit: EventInit = {...defaultInit, ...init}
+    const {target = {}} = eventInit as Event
+    const {value, files, ...targetProperties} = target as Partial<
+      EventTargetWithValue & EventTargetWithFiles
+    >
     if (value !== undefined) {
       setNativeValue(node, value)
     }
@@ -56,15 +84,17 @@ Object.keys(eventMap).forEach(key => {
     } else {
       // IE11 polyfill from https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/CustomEvent#Polyfill
       event = window.document.createEvent(EventType)
-      const {bubbles, cancelable, detail, ...otherInit} = eventInit
+      const {bubbles, cancelable, detail, ...otherInit} = eventInit as Partial<
+        UIEvent
+      >
       event.initEvent(eventName, bubbles, cancelable, detail)
       Object.keys(otherInit).forEach(eventKey => {
         event[eventKey] = otherInit[eventKey]
       })
     }
 
-    const {dataTransfer} = eventInit
-    if (typeof dataTransfer === 'object') {
+    if (isDragEventInit(eventInit)) {
+      const {dataTransfer} = eventInit
       // DataTransfer is not supported in jsdom: https://github.com/jsdom/jsdom/issues/1568
       /* istanbul ignore if  */
       if (typeof window.DataTransfer === 'function') {
@@ -80,7 +110,8 @@ Object.keys(eventMap).forEach(key => {
     return event
   }
 
-  fireEvent[key] = (node, init) => fireEvent(node, createEvent[key](node, init))
+  internalfireEvent[key] = (node: EventTarget, init) =>
+    internalfireEvent(node, createEvent[key](node, init))
 })
 
 // function written after some investigation here:
@@ -102,9 +133,17 @@ function setNativeValue(element, value) {
 
 Object.keys(eventAliasMap).forEach(aliasKey => {
   const key = eventAliasMap[aliasKey]
-  fireEvent[aliasKey] = (...args) => fireEvent[key](...args)
+  internalfireEvent[aliasKey] = (...args) => fireEvent[key](...args)
 })
 
+type FireEventAsFunction = (element: EventTarget, event: Event) => boolean
+type FireEventAsHelper = Record<
+  EventType,
+  (element: EventTarget, init?: unknown) => boolean
+>
+type FireEvent = FireEventAsFunction & FireEventAsHelper
+
+const fireEvent = internalfireEvent as FireEvent
 export {fireEvent, createEvent}
 
 /* eslint complexity:["error", 9] */
diff --git a/src/get-node-text.js b/src/get-node-text.ts
similarity index 81%
rename from src/get-node-text.js
rename to src/get-node-text.ts
index 28b7d3d8..be7f7ef8 100644
--- a/src/get-node-text.js
+++ b/src/get-node-text.ts
@@ -2,9 +2,9 @@
 // https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType#Node_type_constants
 const TEXT_NODE = 3
 
-function getNodeText(node) {
+function getNodeText(node: HTMLElement): string {
   if (node.matches('input[type=submit], input[type=button]')) {
-    return node.value
+    return (node as HTMLInputElement).value
   }
 
   return Array.from(node.childNodes)
diff --git a/src/get-queries-for-element.js b/src/get-queries-for-element.js
deleted file mode 100644
index cc81578b..00000000
--- a/src/get-queries-for-element.js
+++ /dev/null
@@ -1,25 +0,0 @@
-import * as defaultQueries from './queries'
-
-/**
- * @typedef {{[key: string]: Function}} FuncMap
- */
-
-/**
- * @param {HTMLElement} element container
- * @param {FuncMap} queries object of functions
- * @param {Object} initialValue for reducer
- * @returns {FuncMap} returns object of functions bound to container
- */
-function getQueriesForElement(
-  element,
-  queries = defaultQueries,
-  initialValue = {},
-) {
-  return Object.keys(queries).reduce((helpers, key) => {
-    const fn = queries[key]
-    helpers[key] = fn.bind(null, element)
-    return helpers
-  }, initialValue)
-}
-
-export {getQueriesForElement}
diff --git a/src/get-queries-for-element.ts b/src/get-queries-for-element.ts
new file mode 100644
index 00000000..10e8a3a6
--- /dev/null
+++ b/src/get-queries-for-element.ts
@@ -0,0 +1,55 @@
+import * as defaultQueries from './queries'
+
+export type BoundFunction<T> = T extends (
+  attribute: string,
+  element: HTMLElement,
+  text: infer P,
+  options: infer Q,
+) => infer R
+  ? (text: P, options?: Q) => R
+  : T extends (
+      a1: any,
+      text: infer P,
+      options: infer Q,
+      waitForElementOptions: infer W,
+    ) => infer R
+  ? (text: P, options?: Q, waitForElementOptions?: W) => R
+  : T extends (a1: any, text: infer P, options: infer Q) => infer R
+  ? (text: P, options?: Q) => R
+  : never
+export type BoundFunctions<T> = {[P in keyof T]: BoundFunction<T[P]>}
+
+export type Query = (
+  container: HTMLElement,
+  ...args: any[]
+) =>
+  | Error
+  | Promise<HTMLElement[]>
+  | Promise<HTMLElement>
+  | HTMLElement[]
+  | HTMLElement
+  | null
+
+export interface Queries {
+  [T: string]: Query
+}
+
+/**
+ * @param {HTMLElement} element container
+ * @param {FuncMap} queries object of functions
+ * @param {Object} initialValue for reducer
+ * @returns {FuncMap} returns object of functions bound to container
+ */
+function getQueriesForElement<T extends Queries>(
+  element: HTMLElement,
+  queries: Queries = defaultQueries,
+  initialValue = {},
+): BoundFunctions<T> {
+  return Object.keys(queries).reduce((helpers, key) => {
+    const fn: Query = queries[key]
+    helpers[key] = fn.bind(null, element)
+    return helpers
+  }, initialValue) as BoundFunctions<T>
+}
+
+export {getQueriesForElement}
diff --git a/src/helpers.js b/src/helpers.ts
similarity index 96%
rename from src/helpers.js
rename to src/helpers.ts
index 64031562..7237084d 100644
--- a/src/helpers.js
+++ b/src/helpers.ts
@@ -4,7 +4,7 @@ const globalObj = typeof window === 'undefined' ? global : window
 function runWithRealTimers(callback) {
   const usingJestFakeTimers =
     globalObj.setTimeout &&
-    globalObj.setTimeout._isMockFunction &&
+    (globalObj.setTimeout as any)._isMockFunction &&
     typeof jest !== 'undefined'
 
   if (usingJestFakeTimers) {
@@ -46,7 +46,7 @@ function getDocument() {
   }
   return window.document
 }
-function getWindowFromNode(node) {
+function getWindowFromNode(node): Window {
   // istanbul ignore next I'm not sure what could cause the final else so we'll leave it uncovered.
   if (node.defaultView) {
     // node is document
diff --git a/src/index.js b/src/index.ts
similarity index 100%
rename from src/index.js
rename to src/index.ts
diff --git a/src/matches.js b/src/matches.ts
similarity index 67%
rename from src/matches.js
rename to src/matches.ts
index 3241e680..30ddaea1 100644
--- a/src/matches.js
+++ b/src/matches.ts
@@ -1,4 +1,26 @@
-function fuzzyMatches(textToMatch, node, matcher, normalizer) {
+export type MatcherFunction = (content: string, element: HTMLElement) => boolean
+
+export type Matcher = string | RegExp | MatcherFunction
+
+export type NormalizerFn = (text: string) => string
+
+export interface MatcherOptions {
+  exact?: boolean
+  /** Use normalizer with getDefaultNormalizer instead */
+  trim?: boolean
+  /** Use normalizer with getDefaultNormalizer instead */
+  collapseWhitespace?: boolean
+  normalizer?: NormalizerFn
+  /** suppress suggestions for a specific query */
+  suggest?: boolean
+}
+
+function fuzzyMatches(
+  textToMatch: string,
+  node: HTMLElement | null,
+  matcher: Matcher,
+  normalizer: NormalizerFn,
+) {
   if (typeof textToMatch !== 'string') {
     return false
   }
@@ -13,7 +35,12 @@ function fuzzyMatches(textToMatch, node, matcher, normalizer) {
   }
 }
 
-function matches(textToMatch, node, matcher, normalizer) {
+function matches(
+  textToMatch: string | undefined,
+  node: HTMLElement | null,
+  matcher: Matcher,
+  normalizer: NormalizerFn,
+) {
   if (typeof textToMatch !== 'string') {
     return false
   }
@@ -28,7 +55,15 @@ function matches(textToMatch, node, matcher, normalizer) {
   }
 }
 
-function getDefaultNormalizer({trim = true, collapseWhitespace = true} = {}) {
+export interface DefaultNormalizerOptions {
+  trim?: boolean
+  collapseWhitespace?: boolean
+}
+
+function getDefaultNormalizer({
+  trim = true,
+  collapseWhitespace = true,
+}: DefaultNormalizerOptions = {}): NormalizerFn {
   return text => {
     let normalizedText = text
     normalizedText = trim ? normalizedText.trim() : normalizedText
@@ -48,7 +83,7 @@ function getDefaultNormalizer({trim = true, collapseWhitespace = true} = {}) {
  * @param {Function|undefined} normalizer The user-specified normalizer
  * @returns {Function} A normalizer
  */
-function makeNormalizer({trim, collapseWhitespace, normalizer}) {
+function makeNormalizer({trim, collapseWhitespace, normalizer}): NormalizerFn {
   if (normalizer) {
     // User has specified a custom normalizer
     if (
diff --git a/src/pretty-dom.js b/src/pretty-dom.ts
similarity index 61%
rename from src/pretty-dom.js
rename to src/pretty-dom.ts
index 56e8e90d..ee264eef 100644
--- a/src/pretty-dom.js
+++ b/src/pretty-dom.ts
@@ -1,6 +1,15 @@
-import prettyFormat from 'pretty-format'
+import prettyFormat, {OptionsReceived} from 'pretty-format'
 import {getDocument} from './helpers'
 
+// Declare the potential Cypress variable
+declare global {
+  namespace NodeJS {
+    interface Global {
+      Cypress?: any
+    }
+  }
+}
+
 function inCypress(dom) {
   const window =
     (dom.ownerDocument && dom.ownerDocument.defaultView) || undefined
@@ -15,14 +24,24 @@ const inNode = () =>
   process.versions !== undefined &&
   process.versions.node !== undefined
 
-const getMaxLength = dom =>
+const getMaxLength = (dom): number =>
   inCypress(dom)
     ? 0
-    : (typeof process !== 'undefined' && process.env.DEBUG_PRINT_LIMIT) || 7000
+    : (typeof process !== 'undefined' &&
+        parseInt(process.env.DEBUG_PRINT_LIMIT, 10)) ||
+      7000
 
 const {DOMElement, DOMCollection} = prettyFormat.plugins
 
-function prettyDOM(dom, maxLength, options) {
+function isDocument(dom?: Element | Document): dom is Document {
+  return (dom as Document).documentElement !== undefined
+}
+
+function prettyDOM(
+  dom?: Element | Document,
+  maxLength?: number,
+  options?: OptionsReceived,
+) {
   if (!dom) {
     dom = getDocument().body
   }
@@ -33,16 +52,16 @@ function prettyDOM(dom, maxLength, options) {
   if (maxLength === 0) {
     return ''
   }
-  if (dom.documentElement) {
+  if (isDocument(dom)) {
     dom = dom.documentElement
   }
 
-  let domTypeName = typeof dom
+  let domTypeName: string = typeof dom
   if (domTypeName === 'object') {
     domTypeName = dom.constructor.name
   } else {
     // To don't fall with `in` operator
-    dom = {}
+    dom = {} as Element
   }
   if (!('outerHTML' in dom)) {
     throw new TypeError(
@@ -61,6 +80,10 @@ function prettyDOM(dom, maxLength, options) {
     : debugContent
 }
 
-const logDOM = (...args) => console.log(prettyDOM(...args))
+const logDOM = (
+  dom?: Element | HTMLDocument,
+  maxLength?: number,
+  options?: OptionsReceived,
+) => console.log(prettyDOM(dom, maxLength, options))
 
 export {prettyDOM, logDOM}
diff --git a/src/queries/all-utils.js b/src/queries/all-utils.ts
similarity index 100%
rename from src/queries/all-utils.js
rename to src/queries/all-utils.ts
diff --git a/src/queries/alt-text.js b/src/queries/alt-text.ts
similarity index 73%
rename from src/queries/alt-text.js
rename to src/queries/alt-text.ts
index a31c5164..c4e9a3e4 100644
--- a/src/queries/alt-text.js
+++ b/src/queries/alt-text.ts
@@ -1,18 +1,27 @@
 import {wrapAllByQueryWithSuggestion} from '../query-helpers'
 import {checkContainerType} from '../helpers'
-import {matches, fuzzyMatches, makeNormalizer, buildQueries} from './all-utils'
+import {
+  matches,
+  fuzzyMatches,
+  makeNormalizer,
+  buildQueries,
+  MatcherOptions,
+  Matcher,
+} from './all-utils'
 
 function queryAllByAltText(
-  container,
-  alt,
-  {exact = true, collapseWhitespace, trim, normalizer} = {},
+  container: HTMLElement,
+  alt: Matcher,
+  {exact = true, collapseWhitespace, trim, normalizer}: MatcherOptions = {},
 ) {
   checkContainerType(container)
   const matcher = exact ? matches : fuzzyMatches
   const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
-  return Array.from(container.querySelectorAll('img,input,area')).filter(node =>
+  return Array.from(
+    container.querySelectorAll('img,input,area'),
+  ).filter((node: HTMLElement) =>
     matcher(node.getAttribute('alt'), node, alt, matchNormalizer),
-  )
+  ) as HTMLElement[]
 }
 
 const getMultipleError = (c, alt) =>
diff --git a/src/queries/display-value.js b/src/queries/display-value.ts
similarity index 74%
rename from src/queries/display-value.js
rename to src/queries/display-value.ts
index 75ab083f..190db702 100644
--- a/src/queries/display-value.js
+++ b/src/queries/display-value.ts
@@ -6,30 +6,37 @@ import {
   fuzzyMatches,
   makeNormalizer,
   buildQueries,
+  Matcher,
+  MatcherOptions,
 } from './all-utils'
 
+function getElementValue(element: Element): string | undefined {
+  return (element as any).value
+}
+
 function queryAllByDisplayValue(
-  container,
-  value,
-  {exact = true, collapseWhitespace, trim, normalizer} = {},
+  container: HTMLElement,
+  value: Matcher,
+  {exact = true, collapseWhitespace, trim, normalizer}: MatcherOptions = {},
 ) {
   checkContainerType(container)
   const matcher = exact ? matches : fuzzyMatches
   const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
   return Array.from(container.querySelectorAll(`input,textarea,select`)).filter(
-    node => {
+    (node: HTMLElement) => {
       if (node.tagName === 'SELECT') {
-        const selectedOptions = Array.from(node.options).filter(
+        const selectElement = node as HTMLSelectElement
+        const selectedOptions = Array.from(selectElement.options).filter(
           option => option.selected,
         )
         return selectedOptions.some(optionNode =>
           matcher(getNodeText(optionNode), optionNode, value, matchNormalizer),
         )
       } else {
-        return matcher(node.value, node, value, matchNormalizer)
+        return matcher(getElementValue(node), node, value, matchNormalizer)
       }
     },
-  )
+  ) as HTMLElement[]
 }
 
 const getMultipleError = (c, value) =>
diff --git a/src/queries/index.js b/src/queries/index.ts
similarity index 100%
rename from src/queries/index.js
rename to src/queries/index.ts
diff --git a/src/queries/label-text.js b/src/queries/label-text.ts
similarity index 92%
rename from src/queries/label-text.js
rename to src/queries/label-text.ts
index e7eda117..d571d18c 100644
--- a/src/queries/label-text.js
+++ b/src/queries/label-text.ts
@@ -9,13 +9,16 @@ import {
   makeSingleQuery,
   wrapAllByQueryWithSuggestion,
   wrapSingleQueryWithSuggestion,
+  Matcher,
+  MatcherOptions,
+  SelectorMatcherOptions,
 } from './all-utils'
 import {queryAllByText} from './text'
 
 function queryAllLabelsByText(
-  container,
-  text,
-  {exact = true, trim, collapseWhitespace, normalizer} = {},
+  container: HTMLElement,
+  text: Matcher,
+  {exact = true, trim, collapseWhitespace, normalizer}: MatcherOptions = {},
 ) {
   const matcher = exact ? matches : fuzzyMatches
   const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
@@ -35,13 +38,19 @@ function queryAllLabelsByText(
     })
 
     return matcher(textToMatch, label, text, matchNormalizer)
-  })
+  }) as HTMLElement[]
 }
 
 function queryAllByLabelText(
-  container,
-  text,
-  {selector = '*', exact = true, collapseWhitespace, trim, normalizer} = {},
+  container: HTMLElement,
+  text: Matcher,
+  {
+    selector = '*',
+    exact = true,
+    collapseWhitespace,
+    trim,
+    normalizer,
+  }: SelectorMatcherOptions = {},
 ) {
   checkContainerType(container)
 
@@ -51,7 +60,7 @@ function queryAllByLabelText(
     normalizer: matchNormalizer,
   })
   const labelledElements = labels
-    .reduce((matchedElements, label) => {
+    .reduce((matchedElements, label: HTMLLabelElement) => {
       const elementsForLabel = []
       if (label.control) {
         elementsForLabel.push(label.control)
@@ -112,7 +121,7 @@ function queryAllByLabelText(
 
   return Array.from(
     new Set([...labelledElements, ...ariaLabelledElements]),
-  ).filter(element => element.matches(selector))
+  ).filter(element => element.matches(selector)) as HTMLElement[]
 }
 
 // the getAll* query would normally look like this:
diff --git a/src/queries/placeholder-text.js b/src/queries/placeholder-text.ts
similarity index 73%
rename from src/queries/placeholder-text.js
rename to src/queries/placeholder-text.ts
index bdea5945..7fc9a6d9 100644
--- a/src/queries/placeholder-text.js
+++ b/src/queries/placeholder-text.ts
@@ -1,10 +1,19 @@
 import {wrapAllByQueryWithSuggestion} from '../query-helpers'
 import {checkContainerType} from '../helpers'
-import {queryAllByAttribute, buildQueries} from './all-utils'
+import {
+  queryAllByAttribute,
+  buildQueries,
+  Matcher,
+  MatcherOptions,
+} from './all-utils'
 
-function queryAllByPlaceholderText(...args) {
-  checkContainerType(...args)
-  return queryAllByAttribute('placeholder', ...args)
+function queryAllByPlaceholderText(
+  container: HTMLElement,
+  placeholder: Matcher,
+  options?: MatcherOptions,
+) {
+  checkContainerType(container)
+  return queryAllByAttribute('placeholder', container, placeholder, options)
 }
 const getMultipleError = (c, text) =>
   `Found multiple elements with the placeholder text of: ${text}`
diff --git a/src/queries/role.js b/src/queries/role.ts
similarity index 78%
rename from src/queries/role.js
rename to src/queries/role.ts
index 07fe0771..ab77e82d 100644
--- a/src/queries/role.js
+++ b/src/queries/role.ts
@@ -14,12 +14,40 @@ import {
   fuzzyMatches,
   getConfig,
   makeNormalizer,
+  Matcher,
+  MatcherOptions,
   matches,
 } from './all-utils'
 
+export interface ByRoleOptions extends MatcherOptions {
+  /**
+   * If true includes elements in the query set that are usually excluded from
+   * the accessibility tree. `role="none"` or `role="presentation"` are included
+   * in either case.
+   */
+  hidden?: boolean
+  /**
+   * If true only includes elements in the query set that are marked as
+   * selected in the accessibility tree, i.e., `aria-selected="true"`
+   */
+  selected?: boolean
+  /**
+   * Includes every role used in the `role` attribute
+   * For example *ByRole('progressbar', {queryFallbacks: true})` will find <div role="meter progressbar">`.
+   */
+  queryFallbacks?: boolean
+  /**
+   * Only considers  elements with the specified accessible name.
+   */
+  name?:
+    | string
+    | RegExp
+    | ((accessibleName: string, element: Element) => boolean)
+}
+
 function queryAllByRole(
-  container,
-  role,
+  container: HTMLElement,
+  role: Matcher,
   {
     exact = true,
     collapseWhitespace,
@@ -29,7 +57,7 @@ function queryAllByRole(
     normalizer,
     queryFallbacks = false,
     selected,
-  } = {},
+  }: ByRoleOptions = {},
 ) {
   checkContainerType(container)
   const matcher = exact ? matches : fuzzyMatches
@@ -52,7 +80,7 @@ function queryAllByRole(
   }
 
   return Array.from(container.querySelectorAll('*'))
-    .filter(node => {
+    .filter((node: HTMLElement) => {
       const isRoleSpecifiedExplicitly = node.hasAttribute('role')
 
       if (isRoleSpecifiedExplicitly) {
@@ -85,14 +113,14 @@ function queryAllByRole(
       // don't care if aria attributes are unspecified
       return true
     })
-    .filter(element => {
+    .filter((element: HTMLElement) => {
       return hidden === false
         ? isInaccessible(element, {
             isSubtreeInaccessible: cachedIsSubtreeInaccessible,
           }) === false
         : true
     })
-    .filter(element => {
+    .filter((element: HTMLElement) => {
       if (name === undefined) {
         // Don't care
         return true
@@ -104,7 +132,7 @@ function queryAllByRole(
         name,
         text => text,
       )
-    })
+    }) as HTMLElement[]
 }
 
 const getMultipleError = (c, role) =>
@@ -113,16 +141,17 @@ const getMultipleError = (c, role) =>
 const getMissingError = (
   container,
   role,
-  {hidden = getConfig().defaultHidden, name} = {},
+  {hidden = getConfig().defaultHidden, name}: ByRoleOptions = {},
 ) => {
   if (getConfig()._disableExpensiveErrorDiagnostics) {
     return `Unable to find role="${role}"`
   }
 
   let roles = ''
-  Array.from(container.children).forEach(childElement => {
+  Array.from(container.children).forEach((childElement: HTMLElement) => {
     roles += prettyRoles(childElement, {
       hidden,
+      // @ts-ignore FIXME remove this code? prettyRoles does not seem handle 'includeName'
       includeName: name !== undefined,
     })
   })
diff --git a/src/queries/test-id.js b/src/queries/test-id.ts
similarity index 71%
rename from src/queries/test-id.js
rename to src/queries/test-id.ts
index f2ef5a9d..2ab618d5 100644
--- a/src/queries/test-id.js
+++ b/src/queries/test-id.ts
@@ -1,12 +1,22 @@
 import {checkContainerType} from '../helpers'
 import {wrapAllByQueryWithSuggestion} from '../query-helpers'
-import {queryAllByAttribute, getConfig, buildQueries} from './all-utils'
+import {
+  queryAllByAttribute,
+  getConfig,
+  buildQueries,
+  Matcher,
+  MatcherOptions,
+} from './all-utils'
 
 const getTestIdAttribute = () => getConfig().testIdAttribute
 
-function queryAllByTestId(...args) {
-  checkContainerType(...args)
-  return queryAllByAttribute(getTestIdAttribute(), ...args)
+function queryAllByTestId(
+  container: HTMLElement,
+  testId: Matcher,
+  options?: MatcherOptions,
+) {
+  checkContainerType(container)
+  return queryAllByAttribute(getTestIdAttribute(), container, testId, options)
 }
 
 const getMultipleError = (c, id) =>
diff --git a/src/queries/text.js b/src/queries/text.ts
similarity index 80%
rename from src/queries/text.js
rename to src/queries/text.ts
index 903bba25..5cbdfe46 100644
--- a/src/queries/text.js
+++ b/src/queries/text.ts
@@ -1,4 +1,7 @@
-import {wrapAllByQueryWithSuggestion} from '../query-helpers'
+import {
+  SelectorMatcherOptions,
+  wrapAllByQueryWithSuggestion,
+} from '../query-helpers'
 import {checkContainerType} from '../helpers'
 import {DEFAULT_IGNORE_TAGS} from '../config'
 import {
@@ -7,11 +10,16 @@ import {
   makeNormalizer,
   getNodeText,
   buildQueries,
+  Matcher,
 } from './all-utils'
 
+interface ByTextSelectorMatcherOptions extends SelectorMatcherOptions {
+  ignore?: string
+}
+
 function queryAllByText(
-  container,
-  text,
+  container: HTMLElement,
+  text: Matcher,
   {
     selector = '*',
     exact = true,
@@ -19,7 +27,7 @@ function queryAllByText(
     trim,
     ignore = DEFAULT_IGNORE_TAGS,
     normalizer,
-  } = {},
+  }: ByTextSelectorMatcherOptions = {},
 ) {
   checkContainerType(container)
   const matcher = exact ? matches : fuzzyMatches
@@ -30,7 +38,9 @@ function queryAllByText(
   }
   return [...baseArray, ...Array.from(container.querySelectorAll(selector))]
     .filter(node => !ignore || !node.matches(ignore))
-    .filter(node => matcher(getNodeText(node), node, text, matchNormalizer))
+    .filter(node =>
+      matcher(getNodeText(node), node, text, matchNormalizer),
+    ) as HTMLElement[]
 }
 
 const getMultipleError = (c, text) =>
diff --git a/src/queries/title.js b/src/queries/title.ts
similarity index 86%
rename from src/queries/title.js
rename to src/queries/title.ts
index ee304466..f10e740f 100644
--- a/src/queries/title.js
+++ b/src/queries/title.ts
@@ -6,21 +6,23 @@ import {
   makeNormalizer,
   getNodeText,
   buildQueries,
+  Matcher,
+  MatcherOptions,
 } from './all-utils'
 
 function queryAllByTitle(
-  container,
-  text,
-  {exact = true, collapseWhitespace, trim, normalizer} = {},
+  container: HTMLElement,
+  text: Matcher,
+  {exact = true, collapseWhitespace, trim, normalizer}: MatcherOptions = {},
 ) {
   checkContainerType(container)
   const matcher = exact ? matches : fuzzyMatches
   const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
   return Array.from(container.querySelectorAll('[title], svg > title')).filter(
-    node =>
+    (node: HTMLElement) =>
       matcher(node.getAttribute('title'), node, text, matchNormalizer) ||
       matcher(getNodeText(node), node, text, matchNormalizer),
-  )
+  ) as HTMLElement[]
 }
 
 const getMultipleError = (c, title) =>
diff --git a/src/query-helpers.js b/src/query-helpers.ts
similarity index 67%
rename from src/query-helpers.js
rename to src/query-helpers.ts
index cd4c3481..8a090385 100644
--- a/src/query-helpers.js
+++ b/src/query-helpers.ts
@@ -1,13 +1,27 @@
 import {getSuggestedQuery} from './suggestions'
-import {fuzzyMatches, matches, makeNormalizer} from './matches'
-import {waitFor} from './wait-for'
+import {
+  fuzzyMatches,
+  matches,
+  makeNormalizer,
+  Matcher,
+  MatcherOptions,
+} from './matches'
+import {waitFor, WaitForOptions} from './wait-for'
 import {getConfig} from './config'
 
-function getElementError(message, container) {
+export interface SelectorMatcherOptions extends MatcherOptions {
+  ignore?: string
+  selector?: string
+}
+
+function getElementError(message: string, container: HTMLElement): Error {
   return getConfig().getElementError(message, container)
 }
 
-function getMultipleElementsFoundError(message, container) {
+function getMultipleElementsFoundError(
+  message: string,
+  container: HTMLElement,
+): Error {
   return getElementError(
     `${message}\n\n(If this is intentional, then use the \`*AllBy*\` variant of the query (like \`queryAllByText\`, \`getAllByText\`, or \`findAllByText\`)).`,
     container,
@@ -15,20 +29,30 @@ function getMultipleElementsFoundError(message, container) {
 }
 
 function queryAllByAttribute(
-  attribute,
-  container,
-  text,
-  {exact = true, collapseWhitespace, trim, normalizer} = {},
-) {
+  attribute: string,
+  container: HTMLElement,
+  text: Matcher,
+  {exact = true, collapseWhitespace, trim, normalizer}: MatcherOptions = {},
+): HTMLElement[] {
   const matcher = exact ? matches : fuzzyMatches
   const matchNormalizer = makeNormalizer({collapseWhitespace, trim, normalizer})
   return Array.from(container.querySelectorAll(`[${attribute}]`)).filter(node =>
-    matcher(node.getAttribute(attribute), node, text, matchNormalizer),
-  )
+    matcher(
+      node.getAttribute(attribute),
+      node as HTMLElement,
+      text,
+      matchNormalizer,
+    ),
+  ) as HTMLElement[]
 }
 
-function queryByAttribute(attribute, container, text, ...args) {
-  const els = queryAllByAttribute(attribute, container, text, ...args)
+function queryByAttribute(
+  attribute: string,
+  container: HTMLElement,
+  text: Matcher,
+  options?: MatcherOptions,
+): HTMLElement | null {
+  const els = queryAllByAttribute(attribute, container, text, options)
   if (els.length > 1) {
     throw getMultipleElementsFoundError(
       `Found multiple elements by [${attribute}=${text}]`,
@@ -115,6 +139,7 @@ const wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => (
     // get a unique list of all suggestion messages.  We are only going to make a suggestion if
     // all the suggestions are the same
     const uniqueSuggestionMessages = [
+      // @ts-ignore FIXME with the right tsconfig settings
       ...new Set(
         els.map(element => getSuggestedQuery(element, variant)?.toString()),
       ),
@@ -132,7 +157,43 @@ const wrapAllByQueryWithSuggestion = (query, queryAllByName, variant) => (
   return els
 }
 
-function buildQueries(queryAllBy, getMultipleError, getMissingError) {
+/**
+ * query methods have a common call signature. Only the return type differs.
+ */
+export type QueryMethod<Arguments extends any[], Return> = (
+  container: HTMLElement,
+  ...args: Arguments
+) => Return
+export type QueryBy<Arguments extends any[]> = QueryMethod<
+  Arguments,
+  HTMLElement | null
+>
+export type GetAllBy<Arguments extends any[]> = QueryMethod<
+  Arguments,
+  HTMLElement[]
+>
+export type FindAllBy<Arguments extends any[]> = QueryMethod<
+  [Arguments[0], Arguments[1], WaitForOptions],
+  Promise<HTMLElement[]>
+>
+export type GetBy<Arguments extends any[]> = QueryMethod<Arguments, HTMLElement>
+export type FindBy<Arguments extends any[]> = QueryMethod<
+  [Arguments[0], Arguments[1], WaitForOptions],
+  Promise<HTMLElement>
+>
+export type BuiltQueryMethods<Arguments extends any[]> = [
+  QueryBy<Arguments>,
+  GetAllBy<Arguments>,
+  GetBy<Arguments>,
+  FindAllBy<Arguments>,
+  FindBy<Arguments>,
+]
+
+function buildQueries<Arguments extends any[]>(
+  queryAllBy: GetAllBy<Arguments>,
+  getMultipleError: (container: HTMLElement, ...args: Arguments) => string,
+  getMissingError: (container: HTMLElement, ...args: Arguments) => string,
+): BuiltQueryMethods<Arguments> {
   const queryBy = wrapSingleQueryWithSuggestion(
     makeSingleQuery(queryAllBy, getMultipleError),
     queryAllBy.name,
diff --git a/src/role-helpers.js b/src/role-helpers.ts
similarity index 89%
rename from src/role-helpers.js
rename to src/role-helpers.ts
index f42e3e14..4992a21a 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.ts
@@ -8,7 +8,7 @@ const elementRoleList = buildElementRoleList(elementRoles)
  * @param {Element} element -
  * @returns {boolean} - `true` if `element` and its subtree are inaccessible
  */
-function isSubtreeInaccessible(element) {
+function isSubtreeInaccessible(element: HTMLElement): boolean {
   if (element.hidden === true) {
     return true
   }
@@ -25,6 +25,9 @@ function isSubtreeInaccessible(element) {
   return false
 }
 
+interface IsInaccessibleOptions {
+  isSubtreeInaccessible?: typeof isSubtreeInaccessible
+}
 /**
  * Partial implementation https://www.w3.org/TR/wai-aria-1.2/#tree_exclusion
  * which should only be used for elements with a non-presentational role i.e.
@@ -39,7 +42,10 @@ function isSubtreeInaccessible(element) {
  * can be used to return cached results from previous isSubtreeInaccessible calls
  * @returns {boolean} true if excluded, otherwise false
  */
-function isInaccessible(element, options = {}) {
+function isInaccessible(
+  element: HTMLElement,
+  options: IsInaccessibleOptions = {},
+): boolean {
   const {
     isSubtreeInaccessible: isSubtreeInaccessibleImpl = isSubtreeInaccessible,
   } = options
@@ -118,8 +124,8 @@ function buildElementRoleList(elementRolesMap) {
   return result.sort(bySelectorSpecificity)
 }
 
-function getRoles(container, {hidden = false} = {}) {
-  function flattenDOM(node) {
+function getRoles(container, {hidden = false} = {}): Record<string, Element[]> {
+  function flattenDOM(node: ParentNode) {
     return [
       node,
       ...Array.from(node.children).reduce(
@@ -133,8 +139,8 @@ function getRoles(container, {hidden = false} = {}) {
     .filter(element => {
       return hidden === false ? isInaccessible(element) === false : true
     })
-    .reduce((acc, node) => {
-      let roles = []
+    .reduce((acc, node: Element) => {
+      let roles: Array<string> = []
       // TODO: This violates html-aria which does not allow any role on every element
       if (node.hasAttribute('role')) {
         roles = node.getAttribute('role').split(' ').slice(0, 1)
@@ -152,7 +158,7 @@ function getRoles(container, {hidden = false} = {}) {
     }, {})
 }
 
-function prettyRoles(dom, {hidden}) {
+function prettyRoles(dom: HTMLElement, {hidden}) {
   const roles = getRoles(dom, {hidden})
 
   return Object.entries(roles)
@@ -161,7 +167,7 @@ function prettyRoles(dom, {hidden}) {
       const elementsString = elements
         .map(el => {
           const nameString = `Name "${computeAccessibleName(el)}":\n`
-          const domString = prettyDOM(el.cloneNode(false))
+          const domString = prettyDOM(el.cloneNode(false) as Element)
           return `${nameString}${domString}`
         })
         .join('\n\n')
@@ -171,7 +177,7 @@ function prettyRoles(dom, {hidden}) {
     .join('\n')
 }
 
-const logRoles = (dom, {hidden = false} = {}) =>
+const logRoles = (dom: HTMLElement, {hidden = false} = {}) =>
   console.log(prettyRoles(dom, {hidden}))
 
 /**
diff --git a/src/screen.js b/src/screen.ts
similarity index 100%
rename from src/screen.js
rename to src/screen.ts
diff --git a/src/suggestions.js b/src/suggestions.ts
similarity index 69%
rename from src/suggestions.js
rename to src/suggestions.ts
index ff960d68..88e7098b 100644
--- a/src/suggestions.js
+++ b/src/suggestions.ts
@@ -6,10 +6,19 @@ import {getImplicitAriaRoles} from './role-helpers'
 
 const normalize = getDefaultNormalizer()
 
-function getLabelTextFor(element) {
-  let label =
-    element.labels &&
-    Array.from(element.labels).find(el => Boolean(normalize(el.textContent)))
+function isElementWithLabels(
+  element: HTMLElement,
+): element is HTMLInputElement {
+  // We cast with HTMLInputElement, but it could be a HTMLSelectElement
+  return (element as HTMLInputElement).labels !== undefined
+}
+
+function getLabelTextFor(element: HTMLElement): string | undefined {
+  let label: HTMLLabelElement | undefined =
+    isElementWithLabels(element) &&
+    Array.from(element.labels).find((el: HTMLLabelElement) =>
+      Boolean(normalize(el.textContent)),
+    )
 
   // non form elements that are using aria-labelledby won't be included in `element.labels`
   if (!label) {
@@ -30,7 +39,16 @@ function escapeRegExp(string) {
   return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&') // $& means the whole matched string
 }
 
-function makeSuggestion(queryName, content, {variant = 'get', name}) {
+interface MakeSuggestionOptions {
+  variant?: string
+  name?: string
+}
+
+function makeSuggestion(
+  queryName,
+  content,
+  {variant = 'get', name}: MakeSuggestionOptions,
+) {
   const queryArgs = [content]
 
   if (name) {
@@ -55,7 +73,20 @@ function makeSuggestion(queryName, content, {variant = 'get', name}) {
   }
 }
 
-export function getSuggestedQuery(element, variant) {
+function isElementWithValue(element: HTMLElement): element is HTMLInputElement {
+  // We cast with HTMLInputElement, but it could be a HTMLSelectElement
+  return Boolean((element as HTMLInputElement).value)
+}
+
+export interface Suggestion {
+  queryName: string
+  toString(): string
+}
+
+export function getSuggestedQuery(
+  element: HTMLElement,
+  variant?: string,
+): Suggestion | undefined {
   const role =
     element.getAttribute('role') ?? getImplicitAriaRoles(element)?.[0]
   if (role) {
@@ -80,7 +111,7 @@ export function getSuggestedQuery(element, variant) {
     return makeSuggestion('Text', textContent, {variant})
   }
 
-  if (element.value) {
+  if (isElementWithValue(element)) {
     return makeSuggestion('DisplayValue', normalize(element.value), {variant})
   }
 
diff --git a/src/wait-for-dom-change.js b/src/wait-for-dom-change.ts
similarity index 85%
rename from src/wait-for-dom-change.js
rename to src/wait-for-dom-change.ts
index 1344db9d..97076388 100644
--- a/src/wait-for-dom-change.js
+++ b/src/wait-for-dom-change.ts
@@ -7,6 +7,7 @@ import {
   runWithRealTimers,
 } from './helpers'
 import {getConfig} from './config'
+import {WaitForOptions} from './wait-for'
 
 let hasWarned = false
 
@@ -22,7 +23,7 @@ function waitForDomChange({
     attributes: true,
     characterData: true,
   },
-} = {}) {
+}: WaitForOptions = {}) {
   if (!hasWarned) {
     hasWarned = true
     console.warn(
@@ -31,7 +32,9 @@ function waitForDomChange({
   }
   return new Promise((resolve, reject) => {
     const timer = setTimeout(onTimeout, timeout)
-    const {MutationObserver} = getWindowFromNode(container)
+    const {MutationObserver} = getWindowFromNode(container) as Window & {
+      MutationObserver: (callback: MutationCallback) => void
+    }
     const observer = new MutationObserver(onMutation)
     runWithRealTimers(() =>
       observer.observe(container, mutationObserverOptions),
@@ -47,7 +50,7 @@ function waitForDomChange({
       }
     }
 
-    function onMutation(mutationsList) {
+    function onMutation(mutationsList: MutationRecord[]) {
       onDone(null, mutationsList)
     }
 
diff --git a/src/wait-for-element-to-be-removed.js b/src/wait-for-element-to-be-removed.ts
similarity index 75%
rename from src/wait-for-element-to-be-removed.js
rename to src/wait-for-element-to-be-removed.ts
index 0703b575..4a2a38b8 100644
--- a/src/wait-for-element-to-be-removed.js
+++ b/src/wait-for-element-to-be-removed.ts
@@ -1,4 +1,4 @@
-import {waitFor} from './wait-for'
+import {waitFor, WaitForOptions} from './wait-for'
 
 const isRemoved = result => !result || (Array.isArray(result) && !result.length)
 
@@ -12,26 +12,32 @@ function initialCheck(elements) {
   }
 }
 
-async function waitForElementToBeRemoved(callback, options) {
+async function waitForElementToBeRemoved<T extends Node>(
+  callback: (() => T | T[]) | T | T[],
+  options?: WaitForOptions,
+) {
   // created here so we get a nice stacktrace
   const timeoutError = new Error('Timed out in waitForElementToBeRemoved.')
+  let cb
   if (typeof callback !== 'function') {
     initialCheck(callback)
-    const elements = Array.isArray(callback) ? callback : [callback]
+    const elements: Array<T> = Array.isArray(callback) ? callback : [callback]
     const getRemainingElements = elements.map(element => {
       let parent = element.parentElement
       while (parent.parentElement) parent = parent.parentElement
       return () => (parent.contains(element) ? element : null)
     })
-    callback = () => getRemainingElements.map(c => c()).filter(Boolean)
+    cb = () => getRemainingElements.map(c => c()).filter(Boolean)
+  } else {
+    cb = callback
   }
 
-  initialCheck(callback())
+  initialCheck(cb())
 
   return waitFor(() => {
     let result
     try {
-      result = callback()
+      result = cb()
     } catch (error) {
       if (error.name === 'TestingLibraryElementError') {
         return true
diff --git a/src/wait-for-element.js b/src/wait-for-element.ts
similarity index 82%
rename from src/wait-for-element.js
rename to src/wait-for-element.ts
index 060f17be..8bc585d9 100644
--- a/src/wait-for-element.js
+++ b/src/wait-for-element.ts
@@ -1,11 +1,14 @@
-import {waitFor} from './wait-for'
+import {waitFor, WaitForOptions} from './wait-for'
 
 let hasWarned = false
 
 // deprecated... TODO: remove this method. People should use a find* query or
 // wait instead the reasoning is that this doesn't really do anything useful
 // that you can't get from using find* or wait.
-async function waitForElement(callback, options) {
+async function waitForElement<T>(
+  callback: () => T extends Promise<any> ? never : T,
+  options?: WaitForOptions,
+): Promise<T> {
   if (!hasWarned) {
     hasWarned = true
     console.warn(
diff --git a/src/wait-for.js b/src/wait-for.ts
similarity index 80%
rename from src/wait-for.js
rename to src/wait-for.ts
index b271a00d..c77a54c2 100644
--- a/src/wait-for.js
+++ b/src/wait-for.ts
@@ -17,7 +17,7 @@ function copyStackTrace(target, source) {
 function waitFor(
   callback,
   {
-    container = getDocument(),
+    container = getDocument() as Node,
     timeout = getConfig().asyncUtilTimeout,
     showOriginalStackTrace = getConfig().showOriginalStackTrace,
     stackTraceError,
@@ -27,7 +27,7 @@ function waitFor(
       childList: true,
       attributes: true,
       characterData: true,
-    },
+    } as MutationObserverInit,
   },
 ) {
   if (typeof callback !== 'function') {
@@ -40,7 +40,9 @@ function waitFor(
     const overallTimeoutTimer = setTimeout(onTimeout, timeout)
     const intervalId = setInterval(checkCallback, interval)
 
-    const {MutationObserver} = getWindowFromNode(container)
+    const {MutationObserver} = (getWindowFromNode(container) as unknown) as {
+      MutationObserver: (callback: MutationCallback) => void
+    }
     const observer = new MutationObserver(checkCallback)
     runWithRealTimers(() =>
       observer.observe(container, mutationObserverOptions),
@@ -90,7 +92,18 @@ function waitFor(
   })
 }
 
-function waitForWrapper(callback, options) {
+export interface WaitForOptions {
+  container?: Node
+  timeout?: number
+  interval?: number
+  mutationObserverOptions?: MutationObserverInit
+  showOriginalStackTrace?: boolean
+}
+
+function waitForWrapper<T>(
+  callback: () => T extends Promise<any> ? never : T,
+  options?: WaitForOptions,
+): Promise<T> {
   // create the error here so its stack trace is as close to the
   // calling code as possible
   const stackTraceError = new Error('STACK_TRACE_MESSAGE')
@@ -103,16 +116,21 @@ let hasWarned = false
 
 // deprecated... TODO: remove this method. We renamed this to `waitFor` so the
 // code people write reads more clearly.
-function wait(...args) {
+interface WaitOptions {
+  container?: Node
+  timeout?: number
+  interval?: number
+  mutationObserverOptions?: MutationObserverInit
+}
+function wait(first: () => void, options?: WaitOptions): Promise<void> {
   // istanbul ignore next
-  const [first = () => {}, ...rest] = args
   if (!hasWarned) {
     hasWarned = true
     console.warn(
       `\`wait\` has been deprecated and replaced by \`waitFor\` instead. In most cases you should be able to find/replace \`wait\` with \`waitFor\`. Learn more: https://testing-library.com/docs/dom-testing-library/api-async#waitfor.`,
     )
   }
-  return waitForWrapper(first, ...rest)
+  return waitForWrapper(first, options)
 }
 
 export {waitForWrapper as waitFor, wait}
diff --git a/tsconfig.build.json b/tsconfig.build.json
new file mode 100644
index 00000000..3325a603
--- /dev/null
+++ b/tsconfig.build.json
@@ -0,0 +1,7 @@
+{
+  "extends": "./tsconfig.json",
+  "compilerOptions": {
+    "noEmit": false,
+    "emitDeclarationOnly": true
+  }
+}
diff --git a/tsconfig.json b/tsconfig.json
new file mode 100644
index 00000000..406ef8e6
--- /dev/null
+++ b/tsconfig.json
@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "outDir": "./types/",
+    "allowJs": true,
+    "declaration": true,
+    "noEmit": true,
+    "allowSyntheticDefaultImports": true
+  },
+  "include": ["./src/**/*.ts"]
+}
diff --git a/types/config.d.ts b/types/config.d.ts
deleted file mode 100644
index a1fa9fe1..00000000
--- a/types/config.d.ts
+++ /dev/null
@@ -1,14 +0,0 @@
-export interface Config {
-    testIdAttribute: string;
-    asyncWrapper(cb: (...args: any[]) => any): Promise<any>;
-    eventWrapper(cb: (...args: any[]) => any): void;
-    asyncUtilTimeout: number;
-    defaultHidden: boolean;
-    throwSuggestions: boolean;
-}
-
-export interface ConfigFn {
-    (existingConfig: Config): Partial<Config>;
-}
-
-export function configure(configDelta: Partial<Config> | ConfigFn): void;
diff --git a/types/events.d.ts b/types/events.d.ts
deleted file mode 100644
index d9c50cb7..00000000
--- a/types/events.d.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-export type EventType =
-    | 'copy'
-    | 'cut'
-    | 'paste'
-    | 'compositionEnd'
-    | 'compositionStart'
-    | 'compositionUpdate'
-    | 'keyDown'
-    | 'keyPress'
-    | 'keyUp'
-    | 'focus'
-    | 'blur'
-    | 'focusIn'
-    | 'focusOut'
-    | 'change'
-    | 'input'
-    | 'invalid'
-    | 'submit'
-    | 'reset'
-    | 'click'
-    | 'contextMenu'
-    | 'dblClick'
-    | 'drag'
-    | 'dragEnd'
-    | 'dragEnter'
-    | 'dragExit'
-    | 'dragLeave'
-    | 'dragOver'
-    | 'dragStart'
-    | 'drop'
-    | 'mouseDown'
-    | 'mouseEnter'
-    | 'mouseLeave'
-    | 'mouseMove'
-    | 'mouseOut'
-    | 'mouseOver'
-    | 'mouseUp'
-    | 'popState'
-    | 'select'
-    | 'touchCancel'
-    | 'touchEnd'
-    | 'touchMove'
-    | 'touchStart'
-    | 'scroll'
-    | 'wheel'
-    | 'abort'
-    | 'canPlay'
-    | 'canPlayThrough'
-    | 'durationChange'
-    | 'emptied'
-    | 'encrypted'
-    | 'ended'
-    | 'loadedData'
-    | 'loadedMetadata'
-    | 'loadStart'
-    | 'pause'
-    | 'play'
-    | 'playing'
-    | 'progress'
-    | 'rateChange'
-    | 'seeked'
-    | 'seeking'
-    | 'stalled'
-    | 'suspend'
-    | 'timeUpdate'
-    | 'volumeChange'
-    | 'waiting'
-    | 'load'
-    | 'error'
-    | 'animationStart'
-    | 'animationEnd'
-    | 'animationIteration'
-    | 'transitionEnd'
-    | 'doubleClick'
-    | 'pointerOver'
-    | 'pointerEnter'
-    | 'pointerDown'
-    | 'pointerMove'
-    | 'pointerUp'
-    | 'pointerCancel'
-    | 'pointerOut'
-    | 'pointerLeave'
-    | 'gotPointerCapture'
-    | 'lostPointerCapture';
-
-export type FireFunction = (element: Document | Element | Window | Node, event: Event) => boolean;
-export type FireObject = {
-    [K in EventType]: (element: Document | Element | Window | Node, options?: {}) => boolean;
-};
-export type CreateObject = {
-    [K in EventType]: (element: Document | Element | Window | Node, options?: {}) => Event;
-};
-
-export const createEvent: CreateObject;
-export const fireEvent: FireFunction & FireObject;
diff --git a/types/get-node-text.d.ts b/types/get-node-text.d.ts
deleted file mode 100644
index 5c5654b5..00000000
--- a/types/get-node-text.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-export function getNodeText(node: HTMLElement): string;
diff --git a/types/get-queries-for-element.d.ts b/types/get-queries-for-element.d.ts
deleted file mode 100644
index b93adfe1..00000000
--- a/types/get-queries-for-element.d.ts
+++ /dev/null
@@ -1,29 +0,0 @@
-import * as queries from './queries';
-
-export type BoundFunction<T> = T extends (
-    attribute: string,
-    element: HTMLElement,
-    text: infer P,
-    options: infer Q,
-) => infer R
-    ? (text: P, options?: Q) => R
-    : T extends (a1: any, text: infer P, options: infer Q, waitForElementOptions: infer W) => infer R
-    ? (text: P, options?: Q, waitForElementOptions?: W) => R
-    : T extends (a1: any, text: infer P, options: infer Q) => infer R
-    ? (text: P, options?: Q) => R
-    : never;
-export type BoundFunctions<T> = { [P in keyof T]: BoundFunction<T[P]> };
-
-export type Query = (
-    container: HTMLElement,
-    ...args: any[]
-) => Error | Promise<HTMLElement[]> | Promise<HTMLElement> | HTMLElement[] | HTMLElement | null;
-
-export interface Queries {
-    [T: string]: Query;
-}
-
-export function getQueriesForElement<T extends Queries = typeof queries>(
-    element: HTMLElement,
-    queriesToBind?: T,
-): BoundFunctions<T>;
diff --git a/types/index.d.ts b/types/index.d.ts
deleted file mode 100644
index 5b199dcf..00000000
--- a/types/index.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-// TypeScript Version: 3.8
-
-import { getQueriesForElement } from './get-queries-for-element';
-import * as queries from './queries';
-import * as queryHelpers from './query-helpers';
-
-declare const within: typeof getQueriesForElement;
-export { queries, queryHelpers, within };
-
-export * from './queries';
-export * from './query-helpers';
-export * from './screen';
-export * from './wait';
-export * from './wait-for';
-export * from './wait-for-dom-change';
-export * from './wait-for-element';
-export * from './wait-for-element-to-be-removed';
-export * from './matches';
-export * from './get-node-text';
-export * from './events';
-export * from './get-queries-for-element';
-export * from './pretty-dom';
-export * from './role-helpers';
-export * from './config';
-export * from './suggestions';
diff --git a/types/matches.d.ts b/types/matches.d.ts
deleted file mode 100644
index 6454c86a..00000000
--- a/types/matches.d.ts
+++ /dev/null
@@ -1,33 +0,0 @@
-export type MatcherFunction = (content: string, element: HTMLElement) => boolean
-export type Matcher = string | RegExp | MatcherFunction
-
-export type NormalizerFn = (text: string) => string
-
-export interface MatcherOptions {
-  exact?: boolean
-  /** Use normalizer with getDefaultNormalizer instead */
-  trim?: boolean
-  /** Use normalizer with getDefaultNormalizer instead */
-  collapseWhitespace?: boolean
-  normalizer?: NormalizerFn
-  /** suppress suggestions for a specific query */
-  suggest?: boolean
-}
-
-export type Match = (
-  textToMatch: string,
-  node: HTMLElement | null,
-  matcher: Matcher,
-  options?: MatcherOptions,
-) => boolean
-
-export interface DefaultNormalizerOptions {
-  trim?: boolean
-  collapseWhitespace?: boolean
-}
-
-export function getDefaultNormalizer(
-  options?: DefaultNormalizerOptions,
-): NormalizerFn
-
-// N.B. Don't expose fuzzyMatches + matches here: they're not public API
diff --git a/types/pretty-dom.d.ts b/types/pretty-dom.d.ts
deleted file mode 100644
index bca6afb4..00000000
--- a/types/pretty-dom.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-import { OptionsReceived } from 'pretty-format';
-
-export function prettyDOM(dom?: Element | HTMLDocument, maxLength?: number, options?: OptionsReceived): string | false;
-export function logDOM(dom?: Element | HTMLDocument, maxLength?: number, options?: OptionsReceived): void;
diff --git a/types/queries.d.ts b/types/queries.d.ts
deleted file mode 100644
index 92c1b946..00000000
--- a/types/queries.d.ts
+++ /dev/null
@@ -1,139 +0,0 @@
-import { Matcher, MatcherOptions } from './matches';
-import { SelectorMatcherOptions } from './query-helpers';
-import { waitForOptions } from './wait-for';
-
-export type QueryByBoundAttribute = (
-    container: HTMLElement,
-    id: Matcher,
-    options?: MatcherOptions,
-) => HTMLElement | null;
-
-export type AllByBoundAttribute = (container: HTMLElement, id: Matcher, options?: MatcherOptions) => HTMLElement[];
-
-export type FindAllByBoundAttribute = (
-    container: HTMLElement,
-    id: Matcher,
-    options?: MatcherOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement[]>;
-
-export type GetByBoundAttribute = (container: HTMLElement, id: Matcher, options?: MatcherOptions) => HTMLElement;
-
-export type FindByBoundAttribute = (
-    container: HTMLElement,
-    id: Matcher,
-    options?: MatcherOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement>;
-
-export type QueryByText = (container: HTMLElement, id: Matcher, options?: SelectorMatcherOptions) => HTMLElement | null;
-
-export type AllByText = (container: HTMLElement, id: Matcher, options?: SelectorMatcherOptions) => HTMLElement[];
-
-export type FindAllByText = (
-    container: HTMLElement,
-    id: Matcher,
-    options?: SelectorMatcherOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement[]>;
-
-export type GetByText = (container: HTMLElement, id: Matcher, options?: SelectorMatcherOptions) => HTMLElement;
-
-export type FindByText = (
-    container: HTMLElement,
-    id: Matcher,
-    options?: SelectorMatcherOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement>;
-
-export interface ByRoleOptions extends MatcherOptions {
-    /**
-     * If true includes elements in the query set that are usually excluded from
-     * the accessibility tree. `role="none"` or `role="presentation"` are included
-     * in either case.
-     */
-    hidden?: boolean;
-    /**
-     * If true only includes elements in the query set that are marked as
-     * selected in the accessibility tree, i.e., `aria-selected="true"`
-     */
-    selected?: boolean;
-    /**
-     * Includes every role used in the `role` attribute
-     * For example *ByRole('progressbar', {queryFallbacks: true})` will find <div role="meter progressbar">`.
-     */
-    queryFallbacks?: boolean;
-    /**
-     * Only considers  elements with the specified accessible name.
-     */
-    name?: string | RegExp | ((accessibleName: string, element: Element) => boolean);
-}
-
-export type AllByRole = (container: HTMLElement, role: Matcher, options?: ByRoleOptions) => HTMLElement[];
-
-export type GetByRole = (container: HTMLElement, role: Matcher, options?: ByRoleOptions) => HTMLElement;
-
-export type QueryByRole = (container: HTMLElement, role: Matcher, options?: ByRoleOptions) => HTMLElement | null;
-
-export type FindByRole = (
-    container: HTMLElement,
-    role: Matcher,
-    options?: ByRoleOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement>;
-
-export type FindAllByRole = (
-    container: HTMLElement,
-    role: Matcher,
-    options?: ByRoleOptions,
-    waitForElementOptions?: waitForOptions,
-) => Promise<HTMLElement[]>;
-
-export const getByLabelText: GetByText;
-export const getAllByLabelText: AllByText;
-export const queryByLabelText: QueryByText;
-export const queryAllByLabelText: AllByText;
-export const findByLabelText: FindByText;
-export const findAllByLabelText: FindAllByText;
-export const getByPlaceholderText: GetByBoundAttribute;
-export const getAllByPlaceholderText: AllByBoundAttribute;
-export const queryByPlaceholderText: QueryByBoundAttribute;
-export const queryAllByPlaceholderText: AllByBoundAttribute;
-export const findByPlaceholderText: FindByBoundAttribute;
-export const findAllByPlaceholderText: FindAllByBoundAttribute;
-export const getByText: GetByText;
-export const getAllByText: AllByText;
-export const queryByText: QueryByText;
-export const queryAllByText: AllByText;
-export const findByText: FindByText;
-export const findAllByText: FindAllByText;
-export const getByAltText: GetByBoundAttribute;
-export const getAllByAltText: AllByBoundAttribute;
-export const queryByAltText: QueryByBoundAttribute;
-export const queryAllByAltText: AllByBoundAttribute;
-export const findByAltText: FindByBoundAttribute;
-export const findAllByAltText: FindAllByBoundAttribute;
-export const getByTitle: GetByBoundAttribute;
-export const getAllByTitle: AllByBoundAttribute;
-export const queryByTitle: QueryByBoundAttribute;
-export const queryAllByTitle: AllByBoundAttribute;
-export const findByTitle: FindByBoundAttribute;
-export const findAllByTitle: FindAllByBoundAttribute;
-export const getByDisplayValue: GetByBoundAttribute;
-export const getAllByDisplayValue: AllByBoundAttribute;
-export const queryByDisplayValue: QueryByBoundAttribute;
-export const queryAllByDisplayValue: AllByBoundAttribute;
-export const findByDisplayValue: FindByBoundAttribute;
-export const findAllByDisplayValue: FindAllByBoundAttribute;
-export const getByRole: GetByRole;
-export const getAllByRole: AllByRole;
-export const queryByRole: QueryByRole;
-export const queryAllByRole: AllByRole;
-export const findByRole: FindByRole;
-export const findAllByRole: FindAllByRole;
-export const getByTestId: GetByBoundAttribute;
-export const getAllByTestId: AllByBoundAttribute;
-export const queryByTestId: QueryByBoundAttribute;
-export const queryAllByTestId: AllByBoundAttribute;
-export const findByTestId: FindByBoundAttribute;
-export const findAllByTestId: FindAllByBoundAttribute;
diff --git a/types/query-helpers.d.ts b/types/query-helpers.d.ts
deleted file mode 100644
index de50a2d3..00000000
--- a/types/query-helpers.d.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { Matcher, MatcherOptions } from './matches'
-import { waitForOptions } from './wait-for'
-
-export interface SelectorMatcherOptions extends MatcherOptions {
-  selector?: string
-}
-
-export type QueryByAttribute = (
-  attribute: string,
-  container: HTMLElement,
-  id: Matcher,
-  options?: MatcherOptions,
-) => HTMLElement | null
-
-export type AllByAttribute = (
-  attribute: string,
-  container: HTMLElement,
-  id: Matcher,
-  options?: MatcherOptions,
-) => HTMLElement[]
-
-export const queryByAttribute: QueryByAttribute
-export const queryAllByAttribute: AllByAttribute
-export function getElementError(message: string, container: HTMLElement): Error
-
-/**
- * query methods have a common call signature. Only the return type differs.
- */
-export type QueryMethod<Arguments extends any[], Return> = (
-  container: HTMLElement,
-  ...args: Arguments
-) => Return
-export type QueryBy<Arguments extends any[]> = QueryMethod<
-  Arguments,
-  HTMLElement | null
->
-export type GetAllBy<Arguments extends any[]> = QueryMethod<
-  Arguments,
-  HTMLElement[]
->
-export type FindAllBy<Arguments extends any[]> = QueryMethod<
-  [Arguments[0], Arguments[1], waitForOptions],
-  Promise<HTMLElement[]>
->
-export type GetBy<Arguments extends any[]> = QueryMethod<Arguments, HTMLElement>
-export type FindBy<Arguments extends any[]> = QueryMethod<
-  [Arguments[0], Arguments[1], waitForOptions],
-  Promise<HTMLElement>
->
-
-export type BuiltQueryMethods<Arguments extends any[]> = [
-  QueryBy<Arguments>,
-  GetAllBy<Arguments>,
-  GetBy<Arguments>,
-  FindAllBy<Arguments>,
-  FindBy<Arguments>,
-]
-export function buildQueries<Arguments extends any[]>(
-  queryByAll: GetAllBy<Arguments>,
-  getMultipleError: (container: HTMLElement, ...args: Arguments) => string,
-  getMissingError: (container: HTMLElement, ...args: Arguments) => string,
-): BuiltQueryMethods<Arguments>
diff --git a/types/role-helpers.d.ts b/types/role-helpers.d.ts
deleted file mode 100644
index 3dd35b78..00000000
--- a/types/role-helpers.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export function logRoles(container: HTMLElement): string;
-export function getRoles(container: HTMLElement): { [index: string]: HTMLElement[] };
-/**
- * https://testing-library.com/docs/dom-testing-library/api-helpers#isinaccessible
- */
-export function isInaccessible(element: Element): boolean;
diff --git a/types/screen.d.ts b/types/screen.d.ts
deleted file mode 100644
index 2594f5be..00000000
--- a/types/screen.d.ts
+++ /dev/null
@@ -1,17 +0,0 @@
-import { BoundFunctions, Queries } from './get-queries-for-element';
-import * as queries from './queries';
-import { OptionsReceived } from 'pretty-format';
-
-export type Screen<Q extends Queries = typeof queries> = BoundFunctions<Q> & {
-    /**
-     * Convenience function for `pretty-dom` which also allows an array
-     * of elements
-     */
-    debug: (
-        element?: Element | HTMLDocument | Array<Element | HTMLDocument>,
-        maxLength?: number,
-        options?: OptionsReceived,
-    ) => void;
-};
-
-export const screen: Screen;
diff --git a/types/suggestions.d.ts b/types/suggestions.d.ts
deleted file mode 100644
index f574f344..00000000
--- a/types/suggestions.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-export interface Suggestion {
-  queryName: string
-  toString(): string
-}
-
-export function getSuggestedQuery(element: HTMLElement): Suggestion | undefined
diff --git a/types/tslint.json b/types/tslint.json
index 5d45232f..a439c551 100644
--- a/types/tslint.json
+++ b/types/tslint.json
@@ -1,8 +1,14 @@
 {
   "extends": ["dtslint/dtslint.json"],
   "rules": {
+    "one-variable-per-declaration": false,
+    "max-line-length": false,
+    "no-redundant-jsdoc": false,
     "no-useless-files": false,
     "no-relative-import-in-test": false,
-    "semicolon": false
+    "prefer-declare-function": false,
+    "semicolon": false,
+    "strict-export-declare-modifiers": false,
+    "whitespace": false
   }
 }
diff --git a/types/wait-for-dom-change.d.ts b/types/wait-for-dom-change.d.ts
deleted file mode 100644
index 813437f4..00000000
--- a/types/wait-for-dom-change.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { waitForOptions } from "./wait-for";
-
-export function waitForDomChange(options?: waitForOptions): Promise<any>;
diff --git a/types/wait-for-element-to-be-removed.d.ts b/types/wait-for-element-to-be-removed.d.ts
deleted file mode 100644
index b6b1e1bb..00000000
--- a/types/wait-for-element-to-be-removed.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import { waitForOptions } from "./wait-for";
-
-export function waitForElementToBeRemoved<T>(
-    callback: (() => T) | T,
-    options?: waitForOptions,
-): Promise<T>;
diff --git a/types/wait-for-element.d.ts b/types/wait-for-element.d.ts
deleted file mode 100644
index 4fe1de0e..00000000
--- a/types/wait-for-element.d.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { waitForOptions } from "./wait-for";
-
-export function waitForElement<T>(callback: () => T, options?: waitForOptions): Promise<T>;
diff --git a/types/wait-for.d.ts b/types/wait-for.d.ts
deleted file mode 100644
index 0fd0e56a..00000000
--- a/types/wait-for.d.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-export interface waitForOptions {
-  container?: HTMLElement
-  timeout?: number
-  interval?: number
-  mutationObserverOptions?: MutationObserverInit
-}
-
-export function waitFor<T>(
-  callback: () => T extends Promise<any> ? never : T,
-  options?: waitForOptions,
-): Promise<T>
diff --git a/types/wait.d.ts b/types/wait.d.ts
deleted file mode 100644
index 3763e7bd..00000000
--- a/types/wait.d.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export function wait(
-    callback?: () => void,
-    options?: {
-        timeout?: number;
-        interval?: number;
-    },
-): Promise<void>;