Repository: wheresrhys/fetch-mock
Pull request #792 (2024-08-08 23:17:13)

Rhys/convert matchers to ts


Patch:
diff --git a/packages/core/src/CallHistory.ts b/packages/core/src/CallHistory.ts
index 9b5f448..0da8c46 100644
--- a/packages/core/src/CallHistory.ts
+++ b/packages/core/src/CallHistory.ts
@@ -29,7 +29,7 @@ const isName = (filter: CallHistoryFilter): filter is RouteName =>
 
 const isMatchedOrUnmatched = (filter: CallHistoryFilter): filter is (Matched | Unmatched | boolean) =>
 	typeof filter === 'boolean' ||
-	(['matched', 'unmatched']).includes(filter);
+	(['matched', 'unmatched']).includes(filter as string);
 
 class CallHistory {
 	callLogs: CallLog[];
@@ -74,7 +74,7 @@ class CallHistory {
 			) {
 				calls = calls.filter(({ route }) => !route.config.isFallback);
 			} else if (
-				([false, 'unmatched'] as CallHistoryFilter).includes(
+				([false, 'unmatched'] as CallHistoryFilter[]).includes(
 					filter,
 				)
 			) {
diff --git a/packages/core/src/Matchers.ts b/packages/core/src/Matchers.ts
index e673045..a9d6185 100644
--- a/packages/core/src/Matchers.ts
+++ b/packages/core/src/Matchers.ts
@@ -1,21 +1,19 @@
-//@type-check
-/** @typedef {import('./Route.js').RouteConfig} RouteConfig */
-/** @typedef {import('./CallHistory.js').CallLog} CallLog */
+import { RouteConfig} from './Route.js';
+import { CallLog } from './CallHistory.js';
 import glob from 'globrex';
 import * as regexparam from 'regexparam';
 import { isSubsetOf } from 'is-subset-of';
 import { dequal as isEqual } from 'dequal';
 import { normalizeHeaders, getPath, normalizeUrl } from './RequestUtils.js';
 
-/**
- * @typedef URLMatcherObject
- * @property {string} [begin]
- * @property {string} [end]
- * @property {string} [glob]
- * @property {string} [express]
- * @property {string} [path]
- * @property {RegExp} [regexp]
- */
+export type URLMatcherObject = {
+	begin?: string;
+	end?: string;
+	glob?: string;
+	express?: string;
+	path?: string;
+	regexp?: RegExp;
+};
 export type RouteMatcherUrl = string | RegExp | URL | URLMatcherObject;
 type UrlMatcherGenerator = (targetString: string) => RouteMatcherFunction;
 export type RouteMatcherFunction = (callLog: CallLog) => boolean;
@@ -28,26 +26,14 @@ export type MatcherDefinition = {
 	usesBody?: boolean;
 };
 
-/**
- * @param {RouteMatcher | RouteConfig} matcher
- * @returns {matcher is RouteMatcherUrl}
- */
-export const isUrlMatcher = (matcher) =>
+export const isUrlMatcher = (matcher: RouteMatcher | RouteConfig): matcher is RouteMatcherUrl =>
 	matcher instanceof RegExp ||
 	typeof matcher === 'string' ||
 	(typeof matcher === 'object' && 'href' in matcher);
 
-/**
- *
- * @param {RouteMatcher| RouteConfig} matcher
- * @returns {matcher is RouteMatcherFunction}
- */
-export const isFunctionMatcher = (matcher) => typeof matcher === 'function';
+export const isFunctionMatcher = (matcher: RouteMatcher | RouteConfig): matcher is RouteMatcherFunction => typeof matcher === 'function';
 
-/**
- * @type {Object.<string, UrlMatcherGenerator>}
- */
-const stringMatchers = {
+const stringMatchers: { [key: string]: UrlMatcherGenerator } = {
 	begin:
 		(targetString) =>
 		({ url }) =>
@@ -84,10 +70,7 @@ const stringMatchers = {
 		({ url }) =>
 			getPath(url) === targetString,
 };
-/**
- * @type {MatcherGenerator}
- */
-const getHeaderMatcher = ({ headers: expectedHeaders }) => {
+const getHeaderMatcher: MatcherGenerator = ({ headers: expectedHeaders }) => {
 	if (!expectedHeaders) {
 		return;
 	}
@@ -100,10 +83,8 @@ const getHeaderMatcher = ({ headers: expectedHeaders }) => {
 		);
 	};
 };
-/**
- * @type {MatcherGenerator}
- */
-const getMissingHeaderMatcher = ({
+
+const getMissingHeaderMatcher: MatcherGenerator = ({
 	missingHeaders: expectedMissingHeaders,
 }) => {
 	if (!expectedMissingHeaders) {
@@ -117,10 +98,8 @@ const getMissingHeaderMatcher = ({
 		return expectation.every((headerName) => !(headerName in lowerCaseHeaders));
 	};
 };
-/**
- * @type {MatcherGenerator}
- */
-const getMethodMatcher = ({ method: expectedMethod }) => {
+
+const getMethodMatcher: MatcherGenerator = ({ method: expectedMethod }) => {
 	if (!expectedMethod) {
 		return;
 	}
@@ -129,10 +108,8 @@ const getMethodMatcher = ({ method: expectedMethod }) => {
 		return expectedMethod === actualMethod;
 	};
 };
-/**
- * @type {MatcherGenerator}
- */
-const getQueryParamsMatcher = ({ query: passedQuery }) => {
+
+const getQueryParamsMatcher: MatcherGenerator = ({ query: passedQuery }) => {
 	if (!passedQuery) {
 		return;
 	}
@@ -177,10 +154,8 @@ const getQueryParamsMatcher = ({ query: passedQuery }) => {
 		});
 	};
 };
-/**
- * @type {MatcherGenerator}
- */
-const getExpressParamsMatcher = ({ params: expectedParams, url }) => {
+
+const getExpressParamsMatcher: MatcherGenerator = ({ params: expectedParams, url }) => {
 	if (!expectedParams) {
 		return;
 	}
@@ -196,10 +171,8 @@ const getExpressParamsMatcher = ({ params: expectedParams, url }) => {
 		);
 	};
 };
-/**
- * @type {MatcherGenerator}
- */
-const getBodyMatcher = (route) => {
+
+const getBodyMatcher: MatcherGenerator = (route) => {
 	const { body: expectedBody } = route;
 
 	if (!expectedBody) {
@@ -231,28 +204,15 @@ const getBodyMatcher = (route) => {
 	};
 };
 
-/**
- * @type {MatcherGenerator}
- */
-const getFunctionMatcher = ({ matcherFunction }) => matcherFunction;
 
-/**
- * @param {RegExp} regexp
- * @returns {RouteMatcherFunction}
- */
+const getFunctionMatcher: MatcherGenerator = ({ matcherFunction }) => matcherFunction;
+
 const getRegexpMatcher =
-	(regexp) =>
+	(regexp: RegExp): RouteMatcherFunction =>
 	({ url }) =>
 		regexp.test(url);
 
-/**
- *
- * @param {RouteConfig} route
- * @param {string} matcherUrl
- * @param {Object.<string,string>} query
- * @returns {RouteMatcherFunction}
- */
-const getFullUrlMatcher = (route, matcherUrl, query) => {
+const getFullUrlMatcher = (route: RouteConfig, matcherUrl: string, query: { [key: string]: string }): RouteMatcherFunction => {
 	// if none of the special syntaxes apply, it's just a simple string match
 	// but we have to be careful to normalize the url we check and the name
 	// of the route to allow for e.g. http://it.at.there being indistinguishable
@@ -270,10 +230,7 @@ const getFullUrlMatcher = (route, matcherUrl, query) => {
 	};
 };
 
-/**
- * @type {MatcherGenerator}
- */
-const getUrlMatcher = (route) => {
+const getUrlMatcher: MatcherGenerator = (route) => {
 	const { url: matcherUrl, query } = route;
 
 	if (matcherUrl === '*') {
@@ -316,8 +273,7 @@ const getUrlMatcher = (route) => {
 	}
 };
 
-/** @type {MatcherDefinition[]} */
-export const builtInMatchers = [
+export const builtInMatchers: MatcherDefinition[] = [
 	{ name: 'url', matcher: getUrlMatcher },
 	{ name: 'query', matcher: getQueryParamsMatcher },
 	{ name: 'method', matcher: getMethodMatcher },
diff --git a/packages/core/src/RequestUtils.ts b/packages/core/src/RequestUtils.ts
index b11059a..623a37a 100644
--- a/packages/core/src/RequestUtils.ts
+++ b/packages/core/src/RequestUtils.ts
@@ -1,4 +1,5 @@
-// @type-check
+import type { CallLog } from './CallHistory.js';
+
 // https://stackoverflow.com/a/19709846/308237 plus data: scheme
 // split into 2 code paths as URL constructor does not support protocol-relative urls
 const absoluteUrlRX = new RegExp('^[a-z]+://|^data:', 'i');
@@ -12,38 +13,27 @@ interface DerivedRequestOptions {
 
 export type NormalizedRequestOptions = RequestInit | (RequestInit & DerivedRequestOptions);
 
-/** @typedef {import('./CallHistory.js').CallLog} CallLog */
-
-/**
- * @param {string | string | URL} url
- * @returns {string}
- */
-export function normalizeUrl(url) {
+export function normalizeUrl(url: string | String | URL) {
 	if (url instanceof URL) {
 		return url.href;
 	}
-	if (absoluteUrlRX.test(url)) {
-		return new URL(url).href;
+	const primitiveUrl: string = String(url).valueOf();
+
+	if (absoluteUrlRX.test(primitiveUrl)) {
+		return new URL(primitiveUrl).href;
 	}
-	if (protocolRelativeUrlRX.test(url)) {
-		return new URL(url, 'http://dummy').href;
+	if (protocolRelativeUrlRX.test(primitiveUrl)) {
+		return new URL(primitiveUrl, 'http://dummy').href;
 	}
-	const u = new URL(url, 'http://dummy');
-	return u.pathname + u.search;
+	const urlInstance = new URL(primitiveUrl, 'http://dummy');
+	return urlInstance.pathname + urlInstance.search;
 }
 
-/**
- *
- * @param {string | object} url
- * @param {RequestInit} options
- * @returns {CallLog}
- */
-export function createCallLogFromUrlAndOptions(url, options) {
-	/** @type {Promise<any>[]} */
-	const pendingPromises = [];
+export function createCallLogFromUrlAndOptions(url: string | String | object, options: RequestInit): CallLog {
+	const pendingPromises: Promise<any>[]  = [];
 	if (typeof url === 'string' || url instanceof String || url instanceof URL) {
 		// @ts-ignore - jsdoc doesn't distinguish between string and String, but typechecker complains
-		url = normalizeUrl(url);
+		const normalizedUrl: string = normalizeUrl(url);
 		const derivedOptions = options ? { ...options } : {};
 		if (derivedOptions.headers) {
 			derivedOptions.headers = normalizeHeaders(derivedOptions.headers);
@@ -53,8 +43,8 @@ export function createCallLogFromUrlAndOptions(url, options) {
 			: 'get';
 		return {
 			args: [url, options],
-			url,
-			queryParams: new URLSearchParams(getQuery(url)),
+			url: normalizedUrl,
+			queryParams: new URLSearchParams(getQuery(normalizedUrl)),
 			options: derivedOptions,
 			signal: derivedOptions.signal,
 			pendingPromises,
@@ -69,17 +59,9 @@ export function createCallLogFromUrlAndOptions(url, options) {
 	}
 }
 
-/**
- *
- * @param {Request} request
- * @param {RequestInit} options
- * @returns {Promise<CallLog>}
- */
-export async function createCallLogFromRequest(request, options) {
-	/** @type {Promise<any>[]} */
-	const pendingPromises = [];
-	/** @type {NormalizedRequestOptions} */
-	const derivedOptions = {
+export async function createCallLogFromRequest(request: Request, options: RequestInit): Promise<CallLog> {
+	const pendingPromises: Promise<any>[] = [];
+	const derivedOptions: NormalizedRequestOptions = {
 		method: request.method,
 	};
 
@@ -103,34 +85,21 @@ export async function createCallLogFromRequest(request, options) {
 	return callLog;
 }
 
-/**
- * @param {string} url
- * @returns {string}
- */
-export function getPath(url) {
+export function getPath(url: string): string {
 	const u = absoluteUrlRX.test(url)
 		? new URL(url)
 		: new URL(url, 'http://dummy');
 	return u.pathname;
 }
 
-/**
- * @param {string} url
- * @returns {string}
- */
-export function getQuery(url) {
+export function getQuery(url: string): string {
 	const u = absoluteUrlRX.test(url)
 		? new URL(url)
 		: new URL(url, 'http://dummy');
 	return u.search ? u.search.substr(1) : '';
 }
 
-/**
- *
- * @param {HeadersInit | Object.<string, string |number>} headers
- * @returns {Object.<string, string>}
- */
-export const normalizeHeaders = (headers) => {
+export function normalizeHeaders(headers: HeadersInit | { [key: string]: string | number }): { [key: string]: string } {
 	let entries;
 	if (headers instanceof Headers) {
 		entries = [...headers.entries()];
diff --git a/packages/core/src/Route.ts b/packages/core/src/Route.ts
index e5269e9..1257d68 100644
--- a/packages/core/src/Route.ts
+++ b/packages/core/src/Route.ts
@@ -1,14 +1,9 @@
 //@type-check
 import { builtInMatchers } from './Matchers.js';
 import statusTextMap from './StatusTextMap.js';
-
-/** @typedef {import('./Matchers.js').RouteMatcher} RouteMatcher */
-/** @typedef {import('./CallHistory.js').CallLog} CallLog */
-/** @typedef {import('./Matchers.js').RouteMatcherFunction} RouteMatcherFunction */
-/** @typedef {import('./Matchers.js').RouteMatcherUrl} RouteMatcherUrl */
-/** @typedef {import('./Matchers.js').MatcherDefinition} MatcherDefinition */
-/** @typedef {import('./FetchMock.js').FetchMockGlobalConfig} FetchMockGlobalConfig */
-/** @typedef {import('./FetchMock.js').FetchImplementations} FetchImplementations */
+import {RouteMatcher, RouteMatcherFunction, RouteMatcherUrl, MatcherDefinition} from './Matchers.js';
+import type { FetchMockGlobalConfig, FetchImplementations } from './FetchMock.js';
+import type  { CallLog } from './CallHistory.js';
 
 export type UserRouteSpecificConfig = {
   name?: RouteName;
@@ -59,12 +54,7 @@ export type RouteResponseFunction = (arg0: CallLog) => (RouteResponseData | Rout
 export type RouteResponse = RouteResponseData | RouteResponsePromise | RouteResponseFunction;
 export type RouteName = string;
 
-/**
- *
- * @param {number} [status]
- * @returns {number}
- */
-function sanitizeStatus(status) {
+function sanitizeStatus(status?: number): number {
 	if (!status) {
 		return 200;
 	}
@@ -83,10 +73,11 @@ To respond with a JSON object that has status as a property assign the object to
 e.g. {"body": {"status: "registered"}}`);
 }
 
-/**
- * @class Route
- */
 class Route {
+
+  config: RouteConfig;
+  matcher: RouteMatcherFunction;
+  
   constructor(config: RouteConfig) {
 		this.config = config;
 		this.#sanitize();
@@ -96,17 +87,7 @@ class Route {
 		this.#delayResponse();
 	}
 
-	config: RouteConfig;
-  matcher: RouteMatcherFunction;
-	/**
-	 * @returns {void}
-	 */
-	// eslint-disable-next-line class-methods-use-this
-	reset() {}
-
-	/**
-	 * @returns {void}
-	 */
+  reset() {}
 	#validate() {
 		if (['matched', 'unmatched'].includes(this.config.name)) {
 			throw new Error(
@@ -122,17 +103,11 @@ class Route {
 			);
 		}
 	}
-	/**
-	 * @returns {void}
-	 */
 	#sanitize() {
 		if (this.config.method) {
 			this.config.method = this.config.method.toLowerCase();
 		}
 	}
-	/**
-	 * @returns {void}
-	 */
 	#generateMatcher() {
 		const activeMatchers = Route.registeredMatchers
 			.filter(({ name }) => name in this.config)
@@ -145,9 +120,6 @@ class Route {
 		this.matcher = (normalizedRequest) =>
 			activeMatchers.every(({ matcher }) => matcher(normalizedRequest));
 	}
-	/**
-	 * @returns {void}
-	 */
 	#limit() {
 		if (!this.config.repeat) {
 			return;
@@ -165,9 +137,6 @@ class Route {
 			timesLeft = this.config.repeat;
 		};
 	}
-	/**
-	 * @returns {void}
-	 */
 	#delayResponse() {
 		if (this.config.delay) {
 			const { response } = this.config;
@@ -179,12 +148,7 @@ class Route {
 		}
 	}
 
-	/**
-	 *
-	 * @param {RouteResponseConfig} responseInput
-	 * @returns {{response: Response, responseOptions: ResponseInit, responseInput: RouteResponseConfig}}
-	 */
-	constructResponse(responseInput) {
+  constructResponse(responseInput: RouteResponseConfig): { response: Response, responseOptions: ResponseInit, responseInput: RouteResponseConfig } {
 		const responseOptions = this.constructResponseOptions(responseInput);
 		const body = this.constructResponseBody(responseInput, responseOptions);
 
@@ -194,27 +158,17 @@ class Route {
 			responseInput,
 		};
 	}
-	/**
-	 *
-	 * @param {RouteResponseConfig} responseInput
-	 * @returns {ResponseInitUsingHeaders}
-	 */
-	constructResponseOptions(responseInput) {
+  
+  constructResponseOptions(responseInput: RouteResponseConfig): ResponseInitUsingHeaders {
 		const options = responseInput.options || {};
 		options.status = sanitizeStatus(responseInput.status);
 		options.statusText = statusTextMap[options.status];
 		// we use Headers rather than an object because it allows us to add
 		// to them without worrying about case sensitivity of keys
 		options.headers = new this.config.Headers(responseInput.headers);
-		return /** @type {ResponseInitUsingHeaders} */ (options);
+    return options as ResponseInitUsingHeaders;
 	}
-	/**
-	 *
-	 * @param {RouteResponseConfig} responseInput
-	 * @param {ResponseInitUsingHeaders} responseOptions
-	 * @returns {string|null}
-	 */
-	constructResponseBody(responseInput, responseOptions) {
+  constructResponseBody(responseInput: RouteResponseConfig, responseOptions: ResponseInitUsingHeaders): string | null {
 		// start to construct the body
 		let body = responseInput.body;
 		// convert to json if we need to
@@ -244,14 +198,10 @@ class Route {
 		return body || null;
 	}
 
-	/**
-	 * @param {MatcherDefinition} matcher
-	 */
-	static defineMatcher(matcher) {
+  static defineMatcher(matcher: MatcherDefinition) {
 		Route.registeredMatchers.push(matcher);
 	}
-	/** @type {MatcherDefinition[]} */
-	static registeredMatchers = [];
+  static registeredMatchers: MatcherDefinition[] = [];
 }
 
 builtInMatchers.forEach(Route.defineMatcher);
diff --git a/packages/core/src/Router.ts b/packages/core/src/Router.ts
index e1a12b8..10f685f 100644
--- a/packages/core/src/Router.ts
+++ b/packages/core/src/Router.ts
@@ -1,22 +1,13 @@
 //@type-check
-import Route from './Route.js';
+import Route, { UserRouteConfig, RouteResponsePromise, RouteConfig, RouteResponse, RouteResponseData, RouteResponseObjectData, RouteResponseConfig, RouteResponseFunction } from './Route.js';
 import { isUrlMatcher, isFunctionMatcher } from './Matchers.js';
-/** @typedef {import('./Route.js').UserRouteConfig} UserRouteConfig */
-/** @typedef {import('./Route.js').RouteConfig} RouteConfig */
-/** @typedef {import('./Route.js').RouteResponse} RouteResponse */
-/** @typedef {import('./Route.js').RouteResponseData} RouteResponseData */
-/** @typedef {import('./Route.js').RouteResponseObjectData} RouteResponseObjectData */
-/** @typedef {import('./Route.js').RouteResponseConfig} RouteResponseConfig */
-/** @typedef {import('./Route.js').RouteResponseFunction} RouteResponseFunction */
-/** @typedef {import('./Matchers.js').RouteMatcher} RouteMatcher */
-/** @typedef {import('./FetchMock.js').FetchMockConfig} FetchMockConfig */
-/** @typedef {import('./FetchMock.js')} FetchMock */
-/** @typedef {import('./CallHistory.js').CallLog} CallLog */
+import { RouteMatcher } from './Matchers.js';
+import { FetchMockConfig, FetchMock } from './FetchMock.js';
+import type { CallLog } from './CallHistory.js';
 
-/** @typedef {'body' |'headers' |'throws' |'status' |'redirectUrl' } ResponseConfigProp */
+export type ResponseConfigProp = "body" | "headers" | "throws" | "status" | "redirectUrl";
 
-/** @type {ResponseConfigProp[]} */
-const responseConfigProps = [
+const responseConfigProps: ResponseConfigProp[] = [
 	'body',
 	'headers',
 	'throws',
@@ -24,28 +15,15 @@ const responseConfigProps = [
 	'redirectUrl',
 ];
 
-/**
- *
- * @param {RouteConfig | string} options
- * @returns {RouteConfig}
- */
-const nameToOptions = (options) =>
-	typeof options === 'string' ? { name: options } : options;
+function nameToOptions (options: RouteConfig | string): RouteConfig {
+	return typeof options === 'string' ? { name: options } : options;
+}
 
-/**
- *
- * @param {RouteResponse} response
- * @returns {RouteResponse is RouteResponseFunction}
- */
-const isPromise = (response) =>
-	typeof (/** @type {Promise<any>} */ (response).then) === 'function';
+function isPromise (response: RouteResponse): response is RouteResponsePromise {
+	return typeof (response as Promise<any>).then === 'function';
+}
 
-/**
- *
- * @param {RouteResponseData} responseInput
- * @returns {RouteResponseConfig}
- */
-function normalizeResponseInput(responseInput) {
+function normalizeResponseInput(responseInput: RouteResponseData): RouteResponseConfig {
 	// If the response config looks like a status, start to generate a simple response
 	if (typeof responseInput === 'number') {
 		return {
@@ -61,15 +39,10 @@ function normalizeResponseInput(responseInput) {
 			body: responseInput,
 		};
 	}
-	return /** @type{RouteResponseConfig} */ (responseInput);
+	return responseInput as RouteResponseConfig;
 }
 
-/**
- *
- * @param {RouteResponseData} responseInput
- * @returns {boolean}
- */
-function shouldSendAsObject(responseInput) {
+function shouldSendAsObject(responseInput: RouteResponseData): boolean {
 	// if (Object.keys(responseInput).some(key => responseConfigProps.includes(key)) {
 	// 	if (Object.keys(responseInput).some(key => !responseConfigProps.includes(key)) {
 	// 		throw new Error(`Ambiguous whether response is a configuration object `)
@@ -78,12 +51,12 @@ function shouldSendAsObject(responseInput) {
 	// TODO improve this... make it less hacky and magic
 	if (
 		responseConfigProps.some(
-			(prop) => /** @type {RouteResponseConfig}*/ (responseInput)[prop],
+			(prop) => (responseInput as RouteResponseConfig)[prop],
 		)
 	) {
 		if (
 			Object.keys(responseInput).every((key) =>
-				responseConfigProps.includes(/** @type {ResponseConfigProp} */ (key)),
+				responseConfigProps.includes(key as ResponseConfigProp),
 			)
 		) {
 			return false;
@@ -93,11 +66,7 @@ function shouldSendAsObject(responseInput) {
 	return true;
 }
 
-/**
- *
- * @param {CallLog} callLog
- */
-function throwSpecExceptions({ url, options: { headers, method, body } }) {
+function throwSpecExceptions({ url, options: { headers, method, body } }: CallLog) {
 	if (headers) {
 		Object.entries(headers).forEach(([key]) => {
 			if (/\s/.test(key)) {
@@ -117,11 +86,7 @@ function throwSpecExceptions({ url, options: { headers, method, body } }) {
 	}
 }
 
-/**
- * @param {CallLog} callLog
- * @returns
- */
-const resolveUntilResponseConfig = async (callLog) => {
+const resolveUntilResponseConfig = async (callLog: CallLog) => {
 	// We want to allow things like
 	// - function returning a Promise for a response
 	// - delaying (using a timeout Promise) a function's execution to generate
@@ -147,23 +112,13 @@ export default class Router {
 	routes: Route[];
 	config: FetchMockConfig;
 	fallbackRoute: Route;
-	/**
-	 * @param {FetchMockConfig} fetchMockConfig
-	 * @param {object} [inheritedRoutes]
-	 * @param {Route[]} [inheritedRoutes.routes]
-	 * @param {Route} [inheritedRoutes.fallbackRoute]
-	 */
-	constructor(fetchMockConfig, { routes, fallbackRoute } = {}) {
+	constructor(fetchMockConfig: FetchMockConfig, { routes, fallbackRoute }: { routes?: Route[], fallbackRoute?: Route } = {}) {
 		this.config = fetchMockConfig;
 		this.routes = routes || []; // TODO deep clone this??
 		this.fallbackRoute = fallbackRoute;
 	}
-	/**
-	 *
-	 * @param {Request} request
-	 * @returns {boolean}
-	 */
-	needsToReadBody(request) {
+
+	needsToReadBody(request: Request): boolean {
 		return Boolean(
 			request && this.routes.some((route) => route.config.usesBody),
 		);
@@ -236,13 +191,7 @@ export default class Router {
 		});
 	}
 
-	/**
-	 *
-	 * @param {CallLog} callLog
-	 * @returns {Promise<{response: Response, responseOptions: ResponseInit, responseInput: RouteResponseConfig}>}
-	 */
-	// eslint-disable-next-line class-methods-use-this
-	async generateResponse(callLog) {
+	async generateResponse(callLog: CallLog): Promise<{ response: Response, responseOptions: ResponseInit, responseInput: RouteResponseConfig }> {
 		const responseInput = await resolveUntilResponseConfig(callLog);
 		// If the response is a pre-made Response, respond with it
 		if (responseInput instanceof Response) {
@@ -262,23 +211,14 @@ export default class Router {
 
 		return callLog.route.constructResponse(responseConfig);
 	}
-	/**
-	 *
-	 * @param {Response} response
-	 * @param {ResponseInit} responseConfig
-	 * @param {RouteResponseConfig} responseInput
-	 * @param {string} responseUrl
-	 * @param {Promise<any>[]} pendingPromises
-	 * @returns {Response}
-	 */
-	// eslint-disable-next-line class-methods-use-this
+	
 	createObservableResponse(
-		response,
-		responseConfig,
-		responseInput,
-		responseUrl,
-		pendingPromises,
-	) {
+		response: Response,
+		responseConfig: ResponseInit,
+		responseInput: RouteResponseConfig,
+		responseUrl: string,
+		pendingPromises: Promise<any>[],
+	): Response {
 		// Using a proxy means we can set properties that may not be writable on
 		// the original Response. It also means we can track the resolution of
 		// promises returned by res.json(), res.text() etc
@@ -308,7 +248,8 @@ export default class Router {
 							const result = matcherFunction.apply(response, args);
 							if (result.then) {
 								pendingPromises.push(
-									result.catch(/** @type {function(): void} */ () => undefined),
+									//@ts-ignore
+									result.catch(() => undefined),
 								);
 							}
 							return result;
@@ -321,15 +262,10 @@ export default class Router {
 		});
 	}
 
-	/**
-	 * @param {RouteMatcher | UserRouteConfig} matcher
-	 * @param {RouteResponse} [response]
-	 * @param {UserRouteConfig | string} [nameOrOptions]
-	 * @returns {void}
-	 */
-	addRoute(matcher, response, nameOrOptions) {
-		/** @type {RouteConfig} */
-		const config = {};
+	// addRoute(matcher: UserRouteConfig): void;
+	// addRoute(matcher: RouteMatcher, response: RouteResponse, nameOrOptions?: UserRouteConfig | string): void;
+	addRoute(matcher: (RouteMatcher | UserRouteConfig), response?: RouteResponse, nameOrOptions?: (UserRouteConfig | string)): void {
+		const config: RouteConfig = {};
 		if (isUrlMatcher(matcher)) {
 			config.url = matcher;
 		} else if (isFunctionMatcher(matcher)) {
@@ -369,10 +305,7 @@ export default class Router {
 		}
 		this.routes.push(route);
 	}
-	/**
-	 * @param {RouteResponse} [response]
-	 */
-	setFallback(response) {
+	setFallback(response?: RouteResponse) {
 		if (this.fallbackRoute) {
 			console.warn(
 				'calling fetchMock.catch() twice - are you sure you want to overwrite the previous fallback response',
diff --git a/packages/core/types/CallHistory.d.ts b/packages/core/types/CallHistory.d.ts
deleted file mode 100644
index e3a7634..0000000
--- a/packages/core/types/CallHistory.d.ts
+++ /dev/null
@@ -1,38 +0,0 @@
-export default CallHistory;
-export type RouteConfig = import("./Route.js").RouteConfig;
-export type RouteName = import("./Route.js").RouteName;
-export type NormalizedRequestOptions = import("./RequestUtils.js").NormalizedRequestOptions;
-export type RouteMatcher = import("./Matchers.js").RouteMatcher;
-export type FetchMockConfig = import("./FetchMock.js").FetchMockConfig;
-export type CallLog = {
-    args: any[];
-    url: string;
-    options: NormalizedRequestOptions;
-    request?: Request;
-    signal?: AbortSignal;
-    route?: Route;
-    response?: Response;
-    expressParams?: {
-        [x: string]: string;
-    };
-    queryParams?: URLSearchParams;
-    pendingPromises: Promise<any>[];
-};
-export type Matched = "matched";
-export type Unmatched = "unmatched";
-export type CallHistoryFilter = RouteName | Matched | Unmatched | boolean | RouteMatcher;
-declare class CallHistory {
-    constructor(config: FetchMockConfig, router: Router);
-    callLogs: CallLog[];
-    config: import("./FetchMock.js").FetchMockConfig;
-    router: Router;
-    recordCall(callLog: CallLog): void;
-    clear(): void;
-    flush(waitForResponseMethods?: boolean): Promise<void>;
-    calls(filter: CallHistoryFilter, options: RouteConfig): CallLog[];
-    called(filter: CallHistoryFilter, options: RouteConfig): boolean;
-    lastCall(filter: CallHistoryFilter, options: RouteConfig): CallLog;
-    done(routeNames?: RouteName | RouteName[]): boolean;
-}
-import Route from './Route.js';
-import Router from './Router.js';
diff --git a/packages/core/types/FetchMock.d.ts b/packages/core/types/FetchMock.d.ts
deleted file mode 100644
index 8d1e028..0000000
--- a/packages/core/types/FetchMock.d.ts
+++ /dev/null
@@ -1,107 +0,0 @@
-export class FetchMock {
-    constructor(config: FetchMockConfig, router?: Router);
-    config: FetchMockConfig;
-    router: Router;
-    callHistory: CallHistory;
-    createInstance(): FetchMock;
-    fetchHandler(this: FetchMock, requestInput: string | URL | Request, requestInit?: RequestInit): Promise<Response>;
-    route(matcher: UserRouteConfig): FetchMock;
-    route(matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    catch(this: FetchMock, response?: RouteResponse): FetchMock;
-    defineMatcher(matcher: MatcherDefinition): void;
-    removeRoutes(options?: {
-        names?: string[];
-        includeSticky?: boolean;
-        includeFallback?: boolean;
-    }): this;
-    clearHistory(this: FetchMock): FetchMock;
-    sticky: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    once: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    any: (this: FetchMock, response: RouteResponse, options?: UserRouteConfig | string) => FetchMock;
-    anyOnce: (this: FetchMock, response: RouteResponse, options?: UserRouteConfig | string) => FetchMock;
-    get: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    getOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    post: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    postOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    put: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    putOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    delete: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    deleteOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    head: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    headOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    patch: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-    patchOnce: {
-        (this: FetchMock, matcher: UserRouteConfig): FetchMock;
-        (this: FetchMock, matcher: RouteMatcher, response: RouteResponse, options?: UserRouteConfig | string): FetchMock;
-    };
-}
-export default fetchMock;
-export type RouteMatcher = import("./Router.js").RouteMatcher;
-export type RouteName = import("./Route.js").RouteName;
-export type UserRouteConfig = import("./Route.js").UserRouteConfig;
-export type RouteResponse = import("./Router.js").RouteResponse;
-export type MatcherDefinition = import("./Matchers.js").MatcherDefinition;
-export type CallLog = import("./CallHistory.js").CallLog;
-export type RouteResponseFunction = import("./Route.js").RouteResponseFunction;
-export type FetchMockGlobalConfig = {
-    sendAsJson?: boolean;
-    includeContentLength?: boolean;
-    matchPartialBody?: boolean;
-};
-export type FetchImplementations = {
-    fetch?: typeof fetch;
-    Headers?: typeof Headers;
-    Request?: typeof Request;
-    Response?: typeof Response;
-};
-export type FetchMockConfig = FetchMockGlobalConfig & FetchImplementations;
-import Router from './Router.js';
-import CallHistory from './CallHistory.js';
-declare const fetchMock: FetchMockStandalone;
-declare class FetchMockStandalone extends FetchMock {
-    mockGlobal(this: FetchMockStandalone): FetchMockStandalone;
-    unmockGlobal(this: FetchMockStandalone): FetchMockStandalone;
-    spy(this: FetchMockStandalone, matcher?: RouteMatcher | UserRouteConfig, name?: RouteName): FetchMockStandalone;
-    spyGlobal(this: FetchMockStandalone): FetchMockStandalone;
-    createInstance(): FetchMockStandalone;
-    #private;
-}
diff --git a/packages/core/types/InstanceManagement.d.ts b/packages/core/types/InstanceManagement.d.ts
deleted file mode 100644
index 22c63e1..0000000
--- a/packages/core/types/InstanceManagement.d.ts
+++ /dev/null
@@ -1,18 +0,0 @@
-type RequestConstructor = new (input: string | Request, init ?: RequestInit) => Request;
-
-declare type FetchMockCore ={
-    createInstance: () => FetchMock
-    config: FetchMockConfig;
-}
-
-declare type FetchMock = FetchMockCore & Router
-
-// 5. Declaration merging
-// Unlike a type alias, an interface can be defined multiple times, and will be treated as a single interface(with members of all declarations being merged).
-
-// // These two declarations become:
-// // interface Point { x: number; y: number; }
-// interface Point { x: number; }
-// interface Point { y: number; }
-
-// const point: Point = { x: 1, y: 2 };
\ No newline at end of file
diff --git a/packages/core/types/Matchers.d.ts b/packages/core/types/Matchers.d.ts
deleted file mode 100644
index ac395ef..0000000
--- a/packages/core/types/Matchers.d.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-export function isUrlMatcher(matcher: RouteMatcher | RouteConfig): matcher is RouteMatcherUrl;
-export function isFunctionMatcher(matcher: RouteMatcher | RouteConfig): matcher is RouteMatcherFunction;
-export const builtInMatchers: MatcherDefinition[];
-export type RouteConfig = import("./Route.js").RouteConfig;
-export type CallLog = import("./CallHistory.js").CallLog;
-export type URLMatcherObject = {
-    begin?: string;
-    end?: string;
-    glob?: string;
-    express?: string;
-    path?: string;
-    regexp?: RegExp;
-};
-export type RouteMatcherUrl = string | RegExp | URL | URLMatcherObject;
-export type UrlMatcherGenerator = (arg0: string) => RouteMatcherFunction;
-export type RouteMatcherFunction = (arg0: CallLog) => boolean;
-export type MatcherGenerator = (arg0: RouteConfig) => RouteMatcherFunction;
-export type RouteMatcher = RouteMatcherUrl | RouteMatcherFunction;
-export type MatcherDefinition = {
-    name: string;
-    matcher: MatcherGenerator;
-    usesBody?: boolean;
-};
diff --git a/packages/core/types/RequestUtils.d.ts b/packages/core/types/RequestUtils.d.ts
deleted file mode 100644
index 20560f1..0000000
--- a/packages/core/types/RequestUtils.d.ts
+++ /dev/null
@@ -1,19 +0,0 @@
-export function normalizeUrl(url: string | string | URL): string;
-export function createCallLogFromUrlAndOptions(url: string | object, options: RequestInit): CallLog;
-export function createCallLogFromRequest(request: Request, options: RequestInit): Promise<CallLog>;
-export function getPath(url: string): string;
-export function getQuery(url: string): string;
-export function normalizeHeaders(headers: HeadersInit | {
-    [x: string]: string | number;
-}): {
-    [x: string]: string;
-};
-export type DerivedRequestOptions = {
-    method: string;
-    body?: string;
-    headers?: {
-        [key: string]: string;
-    };
-};
-export type NormalizedRequestOptions = RequestInit | (RequestInit & DerivedRequestOptions);
-export type CallLog = import("./CallHistory.js").CallLog;
diff --git a/packages/core/types/Route.d.ts b/packages/core/types/Route.d.ts
deleted file mode 100644
index 6f3d25e..0000000
--- a/packages/core/types/Route.d.ts
+++ /dev/null
@@ -1,72 +0,0 @@
-export default Route;
-export type RouteMatcher = import("./Matchers.js").RouteMatcher;
-export type CallLog = import("./CallHistory.js").CallLog;
-export type RouteMatcherFunction = import("./Matchers.js").RouteMatcherFunction;
-export type RouteMatcherUrl = import("./Matchers.js").RouteMatcherUrl;
-export type MatcherDefinition = import("./Matchers.js").MatcherDefinition;
-export type FetchMockGlobalConfig = import("./FetchMock.js").FetchMockGlobalConfig;
-export type FetchImplementations = import("./FetchMock.js").FetchImplementations;
-export type UserRouteSpecificConfig = {
-    name?: RouteName;
-    method?: string;
-    headers?: {
-        [key: string]: string | number;
-    };
-    missingHeaders?: string[];
-    query?: {
-        [key: string]: string;
-    };
-    params?: {
-        [key: string]: string;
-    };
-    body?: object;
-    matcherFunction?: RouteMatcherFunction;
-    url?: RouteMatcherUrl;
-    response?: RouteResponse | RouteResponseFunction;
-    repeat?: number;
-    delay?: number;
-    sticky?: boolean;
-};
-export type InternalRouteConfig = {
-    usesBody?: boolean;
-    isFallback?: boolean;
-};
-export type UserRouteConfig = UserRouteSpecificConfig & FetchMockGlobalConfig;
-export type RouteConfig = UserRouteConfig & FetchImplementations & InternalRouteConfig;
-export type RouteResponseConfig = {
-    body?: string | {};
-    status?: number;
-    headers?: {
-        [key: string]: string;
-    };
-    throws?: Error;
-    redirectUrl?: string;
-    options?: ResponseInit;
-};
-export type ResponseInitUsingHeaders = {
-    status: number;
-    statusText: string;
-    headers: Headers;
-};
-export type RouteResponseObjectData = RouteResponseConfig | object;
-export type RouteResponseData = Response | number | string | RouteResponseObjectData;
-export type RouteResponsePromise = Promise<RouteResponseData>;
-export type RouteResponseFunction = (arg0: CallLog) => (RouteResponseData | RouteResponsePromise);
-export type RouteResponse = RouteResponseData | RouteResponsePromise | RouteResponseFunction;
-export type RouteName = string;
-declare class Route {
-    static defineMatcher(matcher: MatcherDefinition): void;
-    static registeredMatchers: MatcherDefinition[];
-    constructor(config: RouteConfig);
-    config: RouteConfig;
-    matcher: RouteMatcherFunction | undefined;
-    reset(): void;
-    constructResponse(responseInput: RouteResponseConfig): {
-        response: Response;
-        responseOptions: ResponseInit;
-        responseInput: RouteResponseConfig;
-    };
-    constructResponseOptions(responseInput: RouteResponseConfig): ResponseInitUsingHeaders;
-    constructResponseBody(responseInput: RouteResponseConfig, responseOptions: ResponseInitUsingHeaders): string | null;
-    #private;
-}
diff --git a/packages/core/types/Router.d.ts b/packages/core/types/Router.d.ts
deleted file mode 100644
index 56a6bc7..0000000
--- a/packages/core/types/Router.d.ts
+++ /dev/null
@@ -1,37 +0,0 @@
-export default class Router {
-    constructor(fetchMockConfig: FetchMockConfig, { routes, fallbackRoute }?: {
-        routes?: Route[];
-        fallbackRoute?: Route;
-    });
-    routes: Route[];
-    config: import("./FetchMock.js").FetchMockConfig;
-    fallbackRoute: Route;
-    needsToReadBody(request: Request): boolean;
-    execute(callLog: CallLog): Promise<Response>;
-    generateResponse(callLog: CallLog): Promise<{
-        response: Response;
-        responseOptions: ResponseInit;
-        responseInput: RouteResponseConfig;
-    }>;
-    createObservableResponse(response: Response, responseConfig: ResponseInit, responseInput: RouteResponseConfig, responseUrl: string, pendingPromises: Promise<any>[]): Response;
-    addRoute(matcher: RouteMatcher | UserRouteConfig, response?: RouteResponse, nameOrOptions?: UserRouteConfig | string): void;
-    setFallback(response?: RouteResponse): void;
-    removeRoutes({ names, includeSticky, includeFallback }?: {
-        names?: string[];
-        includeSticky?: boolean;
-        includeFallback?: boolean;
-    }): void;
-}
-export type UserRouteConfig = import("./Route.js").UserRouteConfig;
-export type RouteConfig = import("./Route.js").RouteConfig;
-export type RouteResponse = import("./Route.js").RouteResponse;
-export type RouteResponseData = import("./Route.js").RouteResponseData;
-export type RouteResponseObjectData = import("./Route.js").RouteResponseObjectData;
-export type RouteResponseConfig = import("./Route.js").RouteResponseConfig;
-export type RouteResponseFunction = import("./Route.js").RouteResponseFunction;
-export type RouteMatcher = import("./Matchers.js").RouteMatcher;
-export type FetchMockConfig = import("./FetchMock.js").FetchMockConfig;
-export type FetchMock = typeof import("./FetchMock.js");
-export type CallLog = import("./CallHistory.js").CallLog;
-export type ResponseConfigProp = "body" | "headers" | "throws" | "status" | "redirectUrl";
-import Route from './Route.js';
diff --git a/packages/core/types/StatusTextMap.d.ts b/packages/core/types/StatusTextMap.d.ts
deleted file mode 100644
index eb8c81c..0000000
--- a/packages/core/types/StatusTextMap.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default statusTextMap;
-declare const statusTextMap: {
-    [x: number]: string;
-};
diff --git a/packages/core/types/index.d.ts b/packages/core/types/index.d.ts
deleted file mode 100644
index 79c8611..0000000
--- a/packages/core/types/index.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export default fetchMock;
-export { FetchMock };
-import fetchMock from './FetchMock.js';
-import { FetchMock } from './FetchMock.js';


Test patch:
diff --git a/packages/core/src/__tests__/FetchMock/mock-and-spy.test.js b/packages/core/src/__tests__/FetchMock/mock-and-spy.test.js
index e3367fe..62cad96 100644
--- a/packages/core/src/__tests__/FetchMock/mock-and-spy.test.js
+++ b/packages/core/src/__tests__/FetchMock/mock-and-spy.test.js
@@ -44,7 +44,7 @@ describe('mock and spy', () => {
 			const response = await fetch('http://a.com', { method: 'post' });
 			expect(response.status).toEqual(200);
 			const callLog = fm.callHistory.lastCall();
-			expect(callLog.args).toEqual(['http://a.com/', { method: 'post' }]);
+			expect(callLog.args).toEqual(['http://a.com', { method: 'post' }]);
 		});
 
 		it('restores global fetch', () => {