diff --git a/lib/types/.eslintrc.js b/lib/types/.eslintrc.js
new file mode 100644
index 0000000000000000000000000000000000000000..e60f63cce989a27cbb13058f8484234af1499db8
--- /dev/null
+++ b/lib/types/.eslintrc.js
@@ -0,0 +1,5 @@
+module.exports = {
+  rules: {
+    'import/prefer-default-export': 0,
+  },
+};
diff --git a/lib/types/semver-stable.d.ts b/lib/types/semver-stable.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..d7d58f30fc33897a0e370b23ae50c07517e11b78
--- /dev/null
+++ b/lib/types/semver-stable.d.ts
@@ -0,0 +1,7 @@
+declare module 'semver-stable' {
+  export function is(version: string): boolean;
+
+  export function max(versions: string[]): string;
+
+  export function maxSatisfying(versions: string[], range: string): string;
+}
diff --git a/lib/types/semver-utils.d.ts b/lib/types/semver-utils.d.ts
new file mode 100644
index 0000000000000000000000000000000000000000..402fe0b29ada105ce6ee52a29b233221683e107a
--- /dev/null
+++ b/lib/types/semver-utils.d.ts
@@ -0,0 +1,7 @@
+declare module 'semver-utils' {
+  export function parse(version: string): any;
+
+  export function stringify(veriosn: any): string;
+
+  export function parseRange(range: string): any[];
+}
diff --git a/lib/versioning/cargo/index.js b/lib/versioning/cargo/index.ts
similarity index 67%
rename from lib/versioning/cargo/index.js
rename to lib/versioning/cargo/index.ts
index 063c2e451d41e84c941f90928b11b89fc996cfc2..6446cbcb7a7257b159b434bedc61f1ab66b94af6 100644
--- a/lib/versioning/cargo/index.js
+++ b/lib/versioning/cargo/index.ts
@@ -1,6 +1,7 @@
-const npm = require('../npm');
+import { api as npm } from '../npm';
+import { VersioningApi, RangeStrategy } from '../common';
 
-function convertToCaret(item) {
+function convertToCaret(item: string) {
   // In Cargo, "1.2.3" doesn't mean exactly 1.2.3, it means >= 1.2.3 < 2.0.0
   if (isVersion(item)) {
     // NOTE: Partial versions like '1.2' don't get converted to '^1.2'
@@ -11,17 +12,17 @@ function convertToCaret(item) {
   return item.trim();
 }
 
-function cargo2npm(input) {
+function cargo2npm(input: string) {
   let versions = input.split(',');
   versions = versions.map(convertToCaret);
   return versions.join(' ');
 }
 
-function notEmpty(s) {
+function notEmpty(s: string) {
   return s !== '';
 }
 
-function npm2cargo(input) {
+function npm2cargo(input: string) {
   // Note: this doesn't remove the ^
   const res = input
     .split(' ')
@@ -37,22 +38,23 @@ function npm2cargo(input) {
   return res.join(', ');
 }
 
-const isLessThanRange = (version, range) =>
+const isLessThanRange = (version: string, range: string) =>
   npm.isLessThanRange(version, cargo2npm(range));
 
-const isValid = input => npm.isValid(cargo2npm(input));
+export const isValid = (input: string) => npm.isValid(cargo2npm(input));
 
-const isVersion = input => npm.isVersion(input);
+const isVersion = (input: string) => npm.isVersion(input);
 
-const matches = (version, range) => npm.matches(version, cargo2npm(range));
+const matches = (version: string, range: string) =>
+  npm.matches(version, cargo2npm(range));
 
-const maxSatisfyingVersion = (versions, range) =>
+const maxSatisfyingVersion = (versions: string[], range: string) =>
   npm.maxSatisfyingVersion(versions, cargo2npm(range));
 
-const minSatisfyingVersion = (versions, range) =>
+const minSatisfyingVersion = (versions: string[], range: string) =>
   npm.minSatisfyingVersion(versions, cargo2npm(range));
 
-const isSingleVersion = constraint =>
+const isSingleVersion = (constraint: string) =>
   constraint.trim().startsWith('=') &&
   isVersion(
     constraint
@@ -61,7 +63,12 @@ const isSingleVersion = constraint =>
       .trim()
   );
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   if (rangeStrategy === 'pin' || isSingleVersion(currentValue)) {
     let res = '=';
     if (currentValue.startsWith('= ')) {
@@ -84,7 +91,7 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   return newCargo;
 }
 
-module.exports = {
+export const api: VersioningApi = {
   ...npm,
   getNewValue,
   isLessThanRange,
@@ -94,3 +101,4 @@ module.exports = {
   maxSatisfyingVersion,
   minSatisfyingVersion,
 };
+export default api;
diff --git a/lib/versioning/common.ts b/lib/versioning/common.ts
new file mode 100644
index 0000000000000000000000000000000000000000..cc31d41e48f9506484f009443b96a59f47b1d988
--- /dev/null
+++ b/lib/versioning/common.ts
@@ -0,0 +1,41 @@
+import { SemVer, Range } from 'semver';
+
+export type RangeStrategy =
+  | 'auto'
+  | 'bump'
+  | 'pin'
+  | 'replace'
+  | 'update-lockfile'
+  | 'widen';
+
+export interface VersioningApi {
+  // validation
+  isCompatible(version: string, range?: string): string | boolean | null;
+  isSingleVersion(version: string): string | boolean | null;
+  isStable(version: string): boolean;
+  isValid(version: string): string | boolean | null;
+  isVersion(version: string): string | boolean | null;
+
+  // digestion of version
+  getMajor(version: string | SemVer): null | number;
+  getMinor(version: string | SemVer): null | number;
+  getPatch(version: string | SemVer): null | number;
+
+  // comparison
+  equals(version: string, other: string): boolean;
+  isGreaterThan(version: string, other: string): boolean;
+  isLessThanRange?(version: string, range: string): boolean;
+  maxSatisfyingVersion(versions: string[], range: string): string | null;
+  minSatisfyingVersion(versions: string[], range: string): string | null;
+  getNewValue(
+    currentValue: string,
+    rangeStrategy: RangeStrategy,
+    fromVersion: string,
+    toVersion: string
+  ): string;
+  sortVersions(version: string, other: string): number;
+
+  matches(version: string, range: string | Range): boolean;
+
+  valueToVersion?(version: string): string;
+}
diff --git a/lib/versioning/composer/index.js b/lib/versioning/composer/index.ts
similarity index 67%
rename from lib/versioning/composer/index.js
rename to lib/versioning/composer/index.ts
index 2e3c00991777c7e00a4aa4578754c45a8fe26296..bdbb52de71be4260372785c818829479ed5230e6 100644
--- a/lib/versioning/composer/index.js
+++ b/lib/versioning/composer/index.ts
@@ -1,8 +1,9 @@
-const { coerce } = require('semver');
-const { logger } = require('../../logger');
-const npm = require('../npm');
+import { coerce } from 'semver';
+import { logger } from '../../logger';
+import { api as npm } from '../npm';
+import { VersioningApi, RangeStrategy } from '../common';
 
-function padZeroes(input) {
+function padZeroes(input: string) {
   const sections = input.split('.');
   while (sections.length < 3) {
     sections.push('0');
@@ -10,7 +11,7 @@ function padZeroes(input) {
   return sections.join('.');
 }
 
-function composer2npm(input) {
+function composer2npm(input: string) {
   if (npm.isVersion(input)) {
     return input;
   }
@@ -25,45 +26,57 @@ function composer2npm(input) {
   return output;
 }
 
-const equals = (a, b) => npm.equals(composer2npm(a), composer2npm(b));
+const equals = (a: string, b: string) =>
+  npm.equals(composer2npm(a), composer2npm(b));
 
-const getMajor = version => npm.getMajor(coerce(composer2npm(version)));
+const getMajor = (version: string) =>
+  npm.getMajor(coerce(composer2npm(version)));
 
-const getMinor = version => npm.getMinor(coerce(composer2npm(version)));
+const getMinor = (version: string) =>
+  npm.getMinor(coerce(composer2npm(version)));
 
-const getPatch = version => npm.getPatch(coerce(composer2npm(version)));
+const getPatch = (version: string) =>
+  npm.getPatch(coerce(composer2npm(version)));
 
-const isGreaterThan = (a, b) =>
+const isGreaterThan = (a: string, b: string) =>
   npm.isGreaterThan(composer2npm(a), composer2npm(b));
 
-const isLessThanRange = (version, range) =>
+const isLessThanRange = (version: string, range: string) =>
   npm.isLessThanRange(composer2npm(version), composer2npm(range));
 
-const isSingleVersion = input =>
+const isSingleVersion = (input: string) =>
   input && npm.isSingleVersion(composer2npm(input));
 
-const isStable = version => version && npm.isStable(composer2npm(version));
+const isStable = (version: string) =>
+  version && npm.isStable(composer2npm(version));
 
-const isValid = input => input && npm.isValid(composer2npm(input));
+export const isValid = (input: string) =>
+  input && npm.isValid(composer2npm(input));
 
-const isVersion = input => input && npm.isVersion(composer2npm(input));
+export const isVersion = (input: string) =>
+  input && npm.isVersion(composer2npm(input));
 
-const matches = (version, range) =>
+const matches = (version: string, range: string) =>
   npm.matches(composer2npm(version), composer2npm(range));
 
-const maxSatisfyingVersion = (versions, range) =>
+const maxSatisfyingVersion = (versions: string[], range: string) =>
   npm.maxSatisfyingVersion(versions.map(composer2npm), composer2npm(range));
 
-const minSatisfyingVersion = (versions, range) =>
+const minSatisfyingVersion = (versions: string[], range: string) =>
   npm.minSatisfyingVersion(versions.map(composer2npm), composer2npm(range));
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   if (rangeStrategy === 'pin') {
     return toVersion;
   }
   const toMajor = getMajor(toVersion);
   const toMinor = getMinor(toVersion);
-  let newValue;
+  let newValue: string;
   if (isVersion(currentValue)) {
     newValue = toVersion;
   } else if (
@@ -125,11 +138,11 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   return newValue;
 }
 
-function sortVersions(a, b) {
+function sortVersions(a: string, b: string) {
   return npm.sortVersions(composer2npm(a), composer2npm(b));
 }
 
-module.exports = {
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -147,3 +160,4 @@ module.exports = {
   getNewValue,
   sortVersions,
 };
+export default api;
diff --git a/lib/versioning/docker/index.js b/lib/versioning/docker/index.ts
similarity index 79%
rename from lib/versioning/docker/index.js
rename to lib/versioning/docker/index.ts
index 859e45d7eb98d93d91594b8b9085892296883b02..9f7f4ab4c131f1e256c6b0996f076733431b21f5 100644
--- a/lib/versioning/docker/index.js
+++ b/lib/versioning/docker/index.ts
@@ -1,6 +1,7 @@
-const generic = require('../loose/generic');
+import * as generic from '../loose/generic';
+import { VersioningApi } from '../common';
 
-function parse(version) {
+function parse(version: string) {
   const versionPieces = version.replace(/^v/, '').split('-');
   const prefix = versionPieces.shift();
   const suffix = versionPieces.join('-');
@@ -11,12 +12,12 @@ function parse(version) {
   return { release, suffix };
 }
 
-function valueToVersion(value) {
+function valueToVersion(value: string) {
   // Remove any suffix after '-', e.g. '-alpine'
   return value ? value.split('-')[0] : value;
 }
 
-function compare(version1, vervion2) {
+function compare(version1: string, vervion2: string) {
   const parsed1 = parse(version1);
   const parsed2 = parse(vervion2);
   // istanbul ignore if
@@ -42,7 +43,7 @@ function compare(version1, vervion2) {
   return parsed2.suffix.localeCompare(parsed1.suffix);
 }
 
-function isCompatible(version, range) {
+function isCompatible(version: string, range: string) {
   const parsed1 = parse(version);
   const parsed2 = parse(range);
   return (
@@ -51,7 +52,7 @@ function isCompatible(version, range) {
   );
 }
 
-module.exports = {
+export const api: VersioningApi = {
   ...generic.create({
     parse,
     compare,
@@ -59,3 +60,5 @@ module.exports = {
   isCompatible,
   valueToVersion,
 };
+
+export default api;
diff --git a/lib/versioning/hashicorp/index.js b/lib/versioning/hashicorp/index.ts
similarity index 54%
rename from lib/versioning/hashicorp/index.js
rename to lib/versioning/hashicorp/index.ts
index 8d711a5ebfa89e872e61670158d44f1507beb4de..5ed2786188c9e550b8b104cbeea5b64eaba98f24 100644
--- a/lib/versioning/hashicorp/index.js
+++ b/lib/versioning/hashicorp/index.ts
@@ -1,25 +1,31 @@
-const npm = require('../npm');
+import { api as npm } from '../npm';
+import { VersioningApi, RangeStrategy } from '../common';
 
-function hashicorp2npm(input) {
+function hashicorp2npm(input: string) {
   // The only case incompatible with semver is a "short" ~>, e.g. ~> 1.2
   return input.replace(/~>(\s*\d+\.\d+$)/, '^$1').replace(',', '');
 }
 
-const isLessThanRange = (version, range) =>
+const isLessThanRange = (version: string, range: string) =>
   npm.isLessThanRange(hashicorp2npm(version), hashicorp2npm(range));
 
-const isValid = input => npm.isValid(hashicorp2npm(input));
+export const isValid = (input: string) => npm.isValid(hashicorp2npm(input));
 
-const matches = (version, range) =>
+const matches = (version: string, range: string) =>
   npm.matches(hashicorp2npm(version), hashicorp2npm(range));
 
-const maxSatisfyingVersion = (versions, range) =>
+const maxSatisfyingVersion = (versions: string[], range: string) =>
   npm.maxSatisfyingVersion(versions.map(hashicorp2npm), hashicorp2npm(range));
 
-const minSatisfyingVersion = (versions, range) =>
+const minSatisfyingVersion = (versions: string[], range: string) =>
   npm.minSatisfyingVersion(versions.map(hashicorp2npm), hashicorp2npm(range));
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   // handle specia. ~> 1.2 case
   if (currentValue.match(/(~>\s*)\d+\.\d+$/)) {
     return currentValue.replace(
@@ -30,7 +36,7 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   return npm.getNewValue(currentValue, rangeStrategy, fromVersion, toVersion);
 }
 
-module.exports = {
+export const api: VersioningApi = {
   ...npm,
   isLessThanRange,
   isValid,
@@ -39,3 +45,7 @@ module.exports = {
   minSatisfyingVersion,
   getNewValue,
 };
+
+export const isVersion = api.isVersion;
+
+export default api;
diff --git a/lib/versioning/hex/index.js b/lib/versioning/hex/index.ts
similarity index 67%
rename from lib/versioning/hex/index.js
rename to lib/versioning/hex/index.ts
index 24de039ef52f0646d8ec28f6f2715807119dbb44..1af0860fe2c5361be74b6054171b756bb5829663 100644
--- a/lib/versioning/hex/index.js
+++ b/lib/versioning/hex/index.ts
@@ -1,6 +1,7 @@
-const npm = require('../npm');
+import { api as npm } from '../npm';
+import { VersioningApi, RangeStrategy } from '../common';
 
-function hex2npm(input) {
+function hex2npm(input: string) {
   return input
     .replace(/~>\s*(\d+\.\d+)$/, '^$1')
     .replace(/~>\s*(\d+\.\d+\.\d+)/, '~$1')
@@ -9,7 +10,7 @@ function hex2npm(input) {
     .replace(/!=\s*(\d+\.\d+(\.\d+.*)?)/, '>$1 <$1');
 }
 
-function npm2hex(input) {
+function npm2hex(input: string) {
   const res = input
     .split(' ')
     .map(str => str.trim())
@@ -30,21 +31,26 @@ function npm2hex(input) {
   return output;
 }
 
-const isLessThanRange = (version, range) =>
+const isLessThanRange = (version: string, range: string) =>
   npm.isLessThanRange(hex2npm(version), hex2npm(range));
 
-const isValid = input => npm.isValid(hex2npm(input));
+const isValid = (input: string) => npm.isValid(hex2npm(input));
 
-const matches = (version, range) =>
+const matches = (version: string, range: string) =>
   npm.matches(hex2npm(version), hex2npm(range));
 
-const maxSatisfyingVersion = (versions, range) =>
+const maxSatisfyingVersion = (versions: string[], range: string) =>
   npm.maxSatisfyingVersion(versions.map(hex2npm), hex2npm(range));
 
-const minSatisfyingVersion = (versions, range) =>
+const minSatisfyingVersion = (versions: string[], range: string) =>
   npm.minSatisfyingVersion(versions.map(hex2npm), hex2npm(range));
 
-const getNewValue = (currentValue, rangeStrategy, fromVersion, toVersion) => {
+const getNewValue = (
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) => {
   let newSemver = npm.getNewValue(
     hex2npm(currentValue),
     rangeStrategy,
@@ -55,14 +61,14 @@ const getNewValue = (currentValue, rangeStrategy, fromVersion, toVersion) => {
   if (currentValue.match(/~>\s*(\d+\.\d+)$/))
     newSemver = newSemver.replace(
       /\^\s*(\d+\.\d+)/,
-      (str, p1) => '~> ' + p1.slice(0, -2)
+      (_str, p1) => '~> ' + p1.slice(0, -2)
     );
   else newSemver = newSemver.replace(/~\s*(\d+\.\d+\.\d)/, '~> $1');
 
   return newSemver;
 };
 
-module.exports = {
+export const api: VersioningApi = {
   ...npm,
   isLessThanRange,
   isValid,
@@ -71,3 +77,5 @@ module.exports = {
   minSatisfyingVersion,
   getNewValue,
 };
+
+export default api;
diff --git a/lib/versioning/index.js b/lib/versioning/index.js
deleted file mode 100644
index 55ff6ff4a87e992f0ad95b6a35d23a8689675fac..0000000000000000000000000000000000000000
--- a/lib/versioning/index.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const { logger } = require('../logger');
-const supportedSchemes = require('../config/definitions')
-  .getOptions()
-  .find(option => option.name === 'versionScheme').allowedValues;
-
-const schemes = {};
-
-for (const scheme of supportedSchemes) {
-  schemes[scheme] = require('./' + scheme); // eslint-disable-line
-}
-
-module.exports = {
-  get,
-};
-
-function get(versionScheme) {
-  if (!versionScheme) {
-    logger.debug('Missing versionScheme');
-    return schemes.semver;
-  }
-  const scheme = schemes[versionScheme];
-  if (!scheme) {
-    logger.warn({ versionScheme }, 'Unknown version scheme');
-    return schemes.semver;
-  }
-  return scheme;
-}
diff --git a/lib/versioning/index.ts b/lib/versioning/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..e92da8d1b415e1a31e2aec7d7447333a3807de5a
--- /dev/null
+++ b/lib/versioning/index.ts
@@ -0,0 +1,30 @@
+import { logger } from '../logger';
+import { getOptions } from '../config/definitions';
+import { VersioningApi } from './common';
+
+export * from './common';
+
+const supportedSchemes = getOptions().find(
+  option => option.name === 'versionScheme'
+).allowedValues;
+
+const schemes: Record<string, VersioningApi> = {};
+
+for (const scheme of supportedSchemes) {
+  schemes[scheme] = require('./' + scheme).api; // eslint-disable-line
+}
+
+export { get };
+
+function get(versionScheme: string) {
+  if (!versionScheme) {
+    logger.debug('Missing versionScheme');
+    return schemes.semver;
+  }
+  const scheme = schemes[versionScheme];
+  if (!scheme) {
+    logger.warn({ versionScheme }, 'Unknown version scheme');
+    return schemes.semver;
+  }
+  return scheme;
+}
diff --git a/lib/versioning/ivy/index.js b/lib/versioning/ivy/index.ts
similarity index 79%
rename from lib/versioning/ivy/index.js
rename to lib/versioning/ivy/index.ts
index ffcc1e883c3310d8104977fb00b2a88c415d639a..68d516c88234f3595c33ce7eba485eedde46b88f 100644
--- a/lib/versioning/ivy/index.js
+++ b/lib/versioning/ivy/index.ts
@@ -1,3 +1,12 @@
+import maven from '../maven';
+import { TYPE_QUALIFIER, tokenize, isSubversion } from '../maven/compare';
+import {
+  REV_TYPE_LATEST,
+  REV_TYPE_SUBREV,
+  parseDynamicRevision,
+} from './parse';
+import { VersioningApi } from '../common';
+
 const {
   equals,
   getMajor,
@@ -11,24 +20,16 @@ const {
   minSatisfyingVersion,
   getNewValue,
   sortVersions,
-} = require('../maven/index');
-
-const { TYPE_QUALIFIER, tokenize, isSubversion } = require('../maven/compare');
+} = maven;
 
-const {
-  REV_TYPE_LATEST,
-  REV_TYPE_SUBREV,
-  parseDynamicRevision,
-} = require('./parse');
-
-function isVersion(str) {
+function isVersion(str: string) {
   if (!str) {
     return false;
   }
   return isSingleVersion(str) || !!parseDynamicRevision(str);
 }
 
-function matches(a, b) {
+function matches(a: string, b: string) {
   if (!a) return false;
   if (!b) return false;
   const dynamicRevision = parseDynamicRevision(b);
@@ -54,7 +55,7 @@ function matches(a, b) {
   return mavenMatches(a, value);
 }
 
-module.exports = {
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -71,3 +72,5 @@ module.exports = {
   getNewValue,
   sortVersions,
 };
+
+export default api;
diff --git a/lib/versioning/ivy/parse.js b/lib/versioning/ivy/parse.ts
similarity index 76%
rename from lib/versioning/ivy/parse.js
rename to lib/versioning/ivy/parse.ts
index d08d80d18dc19e80fec67e759874bedf9c3cfec9..e5123baf52f61aaaa6cbc4984d6def673bcea2ac 100644
--- a/lib/versioning/ivy/parse.js
+++ b/lib/versioning/ivy/parse.ts
@@ -1,10 +1,16 @@
-const { isSingleVersion, parseRange, rangeToStr } = require('../maven/compare');
+import { isSingleVersion, parseRange, rangeToStr } from '../maven/compare';
 
 const REV_TYPE_LATEST = 'REV_TYPE_LATEST';
 const REV_TYPE_SUBREV = 'REV_TYPE_SUBREVISION';
 const REV_TYPE_RANGE = 'REV_TYPE_RANGE';
 
-function parseDynamicRevision(str) {
+export interface Revision {
+  type: typeof REV_TYPE_LATEST | typeof REV_TYPE_RANGE | typeof REV_TYPE_SUBREV;
+
+  value: string;
+}
+
+function parseDynamicRevision(str: string): Revision {
   if (!str) return null;
 
   const LATEST_REGEX = /^latest\.|^latest$/i;
@@ -38,7 +44,7 @@ function parseDynamicRevision(str) {
   return null;
 }
 
-module.exports = {
+export {
   REV_TYPE_LATEST,
   REV_TYPE_SUBREV,
   REV_TYPE_RANGE,
diff --git a/lib/versioning/loose/generic.js b/lib/versioning/loose/generic.ts
similarity index 53%
rename from lib/versioning/loose/generic.js
rename to lib/versioning/loose/generic.ts
index e286720bd17740bc5b624e67be8af66ec36c09cf..f9bd102cae90480aaf0c2d577856561e749bccbf 100644
--- a/lib/versioning/loose/generic.js
+++ b/lib/versioning/loose/generic.ts
@@ -1,12 +1,32 @@
+import { VersioningApi, RangeStrategy } from '../common';
+
+export interface GenericVersion {
+  release: number[];
+  suffix?: string;
+}
+export interface VersionParser {
+  (version: string);
+}
+
+export interface VersionComparator {
+  (version: string, other: string): number;
+}
+
 // helper functions to ease create other versioning schemas with little code
 // especially if those schemas do not support ranges
-exports.create = ({ parse, compare }) => {
-  let schema = {};
+export const create = ({
+  parse,
+  compare,
+}: {
+  parse: VersionParser;
+  compare: VersionComparator;
+}) => {
+  let schema: VersioningApi = {} as any;
   if (parse) {
-    schema = { ...schema, ...exports.parser(parse) };
+    schema = { ...schema, ...parser(parse) };
   }
   if (compare) {
-    schema = { ...schema, ...exports.comparer(compare) };
+    schema = { ...schema, ...comparer(compare) };
   }
   return schema;
 };
@@ -14,27 +34,27 @@ exports.create = ({ parse, compare }) => {
 // since this file was meant for no range support, a range = version
 // parse should return null if version not valid
 // parse should return an object with property release, an array of version sections major.minor.patch
-exports.parser = parse => {
-  function isValid(version) {
+export const parser = (parse: VersionParser): Partial<VersioningApi> => {
+  function isValid(version: string) {
     if (!version) {
       return null;
     }
     const parsed = parse(version);
     return parsed ? version : null;
   }
-  function getSection(version, index) {
+  function getSection(version: string, index: number) {
     const parsed = parse(version);
     return parsed && parsed.release.length > index
       ? parsed.release[index]
       : null;
   }
-  function getMajor(version) {
+  function getMajor(version: string) {
     return getSection(version, 0);
   }
-  function getMinor(version) {
+  function getMinor(version: string) {
     return getSection(version, 1);
   }
-  function getPatch(version) {
+  function getPatch(version: string) {
     return getSection(version, 2);
   }
 
@@ -42,7 +62,7 @@ exports.parser = parse => {
     // validation
     isCompatible: isValid,
     isSingleVersion: isValid,
-    isStable: isValid,
+    isStable: v => !!isValid(v),
     isValid,
     isVersion: isValid,
     // digestion of version
@@ -54,29 +74,36 @@ exports.parser = parse => {
 
 // this is the main reason this file was created
 // most operations below could be derived from a compare function
-exports.comparer = compare => {
-  function equals(version, other) {
+export const comparer = (
+  compare: VersionComparator
+): Partial<VersioningApi> => {
+  function equals(version: string, other: string) {
     return compare(version, other) === 0;
   }
 
-  function isGreaterThan(version, other) {
+  function isGreaterThan(version: string, other: string) {
     return compare(version, other) > 0;
   }
-  function isLessThanRange(version, range) {
+  function isLessThanRange(version: string, range: string) {
     return compare(version, range) < 0;
   }
 
   // we don't not have ranges, so versions has to be equal
-  function maxSatisfyingVersion(versions, range) {
+  function maxSatisfyingVersion(versions: string[], range: string) {
     return versions.find(v => equals(v, range)) || null;
   }
-  function minSatisfyingVersion(versions, range) {
+  function minSatisfyingVersion(versions: string[], range: string) {
     return versions.find(v => equals(v, range)) || null;
   }
-  function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+  function getNewValue(
+    _currentValue: string,
+    _rangeStrategy: RangeStrategy,
+    _fromVersion: string,
+    toVersion: string
+  ) {
     return toVersion;
   }
-  function sortVersions(version, other) {
+  function sortVersions(version: string, other: string) {
     return compare(version, other);
   }
 
diff --git a/lib/versioning/loose/index.js b/lib/versioning/loose/index.ts
similarity index 79%
rename from lib/versioning/loose/index.js
rename to lib/versioning/loose/index.ts
index 83995868f03c5e0f1914f5ba22dc67ceb314e0fb..9c6f53985b74e15e762517d3d25a784297638d00 100644
--- a/lib/versioning/loose/index.js
+++ b/lib/versioning/loose/index.ts
@@ -1,8 +1,9 @@
-const generic = require('./generic');
+import * as generic from './generic';
+import { VersioningApi } from '../common';
 
 const pattern = /^v?(\d+(?:\.\d+)*)(.*)$/;
 
-function parse(version) {
+function parse(version: string) {
   const matches = pattern.exec(version);
   if (!matches) {
     return null;
@@ -15,7 +16,7 @@ function parse(version) {
   return { release, suffix: suffix || '' };
 }
 
-function compare(version1, vervion2) {
+function compare(version1: string, vervion2: string) {
   const parsed1 = parse(version1);
   const parsed2 = parse(vervion2);
   // istanbul ignore if
@@ -41,7 +42,9 @@ function compare(version1, vervion2) {
   return parsed1.suffix.localeCompare(parsed2.suffix);
 }
 
-module.exports = generic.create({
+export const api: VersioningApi = generic.create({
   parse,
   compare,
 });
+
+export default api;
diff --git a/lib/versioning/maven/compare.js b/lib/versioning/maven/compare.ts
similarity index 75%
rename from lib/versioning/maven/compare.js
rename to lib/versioning/maven/compare.ts
index 1ce7fbeff4aefbb227bd392f2482fb0b6c96fcfe..621803733cc3987ac27f3635d8e98dee931f605d 100644
--- a/lib/versioning/maven/compare.js
+++ b/lib/versioning/maven/compare.ts
@@ -4,7 +4,26 @@ const PREFIX_HYPHEN = 'PREFIX_HYPHEN';
 const TYPE_NUMBER = 'TYPE_NUMBER';
 const TYPE_QUALIFIER = 'TYPE_QUALIFIER';
 
-function iterateChars(str, cb) {
+export interface BaseToken {
+  prefix: string;
+  type: typeof TYPE_NUMBER | typeof TYPE_QUALIFIER;
+  val: number | string;
+  isTransition?: boolean;
+}
+
+export interface NumberToken extends BaseToken {
+  type: typeof TYPE_NUMBER;
+  val: number;
+}
+
+export interface QualifierToken extends BaseToken {
+  type: typeof TYPE_QUALIFIER;
+  val: string;
+}
+
+export type Token = NumberToken | QualifierToken;
+
+function iterateChars(str: string, cb: (p: string, n: string) => void) {
   let prev = null;
   let next = null;
   for (let i = 0; i < str.length; i += 1) {
@@ -15,22 +34,22 @@ function iterateChars(str, cb) {
   cb(prev, null);
 }
 
-function isDigit(char) {
+function isDigit(char: string) {
   return /^\d$/.test(char);
 }
 
-function isLetter(char) {
+function isLetter(char: string) {
   return /^[a-z]$/i.test(char);
 }
 
-function isTransition(prevChar, nextChar) {
+function isTransition(prevChar: string, nextChar: string) {
   return (
     (isDigit(prevChar) && isLetter(nextChar)) ||
     (isLetter(prevChar) && isDigit(nextChar))
   );
 }
 
-function iterateTokens(versionStr, cb) {
+function iterateTokens(versionStr: string, cb: (token: Token) => void) {
   let currentPrefix = PREFIX_HYPHEN;
   let currentVal = '';
 
@@ -74,21 +93,21 @@ function iterateTokens(versionStr, cb) {
   });
 }
 
-function isNull(token) {
+function isNull(token: Token) {
   const val = token.val;
   return val === 0 || val === '' || val === 'final' || val === 'ga';
 }
 
-const zeroToken = {
+const zeroToken: NumberToken = {
   prefix: PREFIX_HYPHEN,
   type: TYPE_NUMBER,
   val: 0,
   isTransition: false,
 };
 
-function tokenize(versionStr) {
-  let buf = [];
-  let result = [];
+function tokenize(versionStr: string) {
+  let buf: Token[] = [];
+  let result: Token[] = [];
   let leadingZero = true;
   iterateTokens(versionStr.toLowerCase().replace(/^v/i, ''), token => {
     if (token.prefix === PREFIX_HYPHEN) {
@@ -107,15 +126,21 @@ function tokenize(versionStr) {
   return result.length ? result : [zeroToken];
 }
 
-function nullFor(token) {
-  return {
-    prefix: token.prefix,
-    type: token.prefix === PREFIX_DOT ? TYPE_NUMBER : TYPE_QUALIFIER,
-    val: token.prefix === PREFIX_DOT ? 0 : '',
-  };
+function nullFor(token: Token): Token {
+  return token.prefix === PREFIX_DOT
+    ? {
+        prefix: token.prefix,
+        type: TYPE_NUMBER,
+        val: 0,
+      }
+    : {
+        prefix: token.prefix,
+        type: TYPE_QUALIFIER,
+        val: '',
+      };
 }
 
-function commonOrder(token) {
+function commonOrder(token: Token) {
   if (token.prefix === PREFIX_DOT && token.type === TYPE_QUALIFIER) {
     return 0;
   }
@@ -128,7 +153,7 @@ function commonOrder(token) {
   return 3;
 }
 
-function qualifierOrder(token) {
+function qualifierOrder(token: Token) {
   const val = token.val;
   if (val === 'alpha' || (token.isTransition && val === 'a')) {
     return 1;
@@ -154,7 +179,7 @@ function qualifierOrder(token) {
   return null;
 }
 
-function qualifierCmp(left, right) {
+function qualifierCmp(left: Token, right: Token) {
   const leftOrder = qualifierOrder(left);
   const rightOrder = qualifierOrder(right);
   if (leftOrder && rightOrder) {
@@ -176,7 +201,7 @@ function qualifierCmp(left, right) {
   return 1;
 }
 
-function tokenCmp(left, right) {
+function tokenCmp(left: Token, right: Token) {
   if (left.prefix === right.prefix) {
     if (left.type === TYPE_NUMBER && right.type === TYPE_NUMBER) {
       if (left.val === right.val) {
@@ -207,7 +232,7 @@ function tokenCmp(left, right) {
   return 1;
 }
 
-function compare(left, right) {
+function compare(left: string, right: string) {
   const leftTokens = tokenize(left);
   const rightTokens = tokenize(right);
   const length = Math.max(leftTokens.length, rightTokens.length);
@@ -220,8 +245,7 @@ function compare(left, right) {
   return 0;
 }
 
-function isVersion(version) {
-  // istanbul ignore if
+function isVersion(version: string) {
   if (!version) return false;
   if (!/^[a-z0-9.-]+$/i.test(version)) return false;
   if (/^[.-]/.test(version)) return false;
@@ -230,7 +254,7 @@ function isVersion(version) {
   return !!tokens.length;
 }
 
-function isValid(str) {
+function isValid(str: string) {
   if (!str) {
     return false;
   }
@@ -240,8 +264,17 @@ function isValid(str) {
 const INCLUDING_POINT = 'INCLUDING_POINT';
 const EXCLUDING_POINT = 'EXCLUDING_POINT';
 
-function parseRange(rangeStr) {
-  function emptyInterval() {
+export interface Range {
+  leftType: typeof INCLUDING_POINT | typeof EXCLUDING_POINT;
+  leftValue: string;
+  leftBracket: string;
+  rightType: typeof INCLUDING_POINT | typeof EXCLUDING_POINT;
+  rightValue: string;
+  rightBracket: string;
+}
+
+function parseRange(rangeStr: string) {
+  function emptyInterval(): Range {
     return {
       leftType: null,
       leftValue: null,
@@ -253,7 +286,7 @@ function parseRange(rangeStr) {
   }
 
   const commaSplit = rangeStr.split(',');
-  let result = [];
+  let result: Range[] = [];
   let interval = emptyInterval();
 
   commaSplit.forEach(subStr => {
@@ -306,38 +339,41 @@ function parseRange(rangeStr) {
   if (!result || !result.length) return null;
 
   const lastIdx = result.length - 1;
-  let prevValue = null;
-  return result.reduce((acc, range, idx) => {
-    const { leftType, leftValue, rightType, rightValue } = range;
-
-    if (idx === 0 && leftValue === '') {
-      if (leftType === EXCLUDING_POINT && isVersion(rightValue)) {
-        prevValue = rightValue;
-        return [...acc, { ...range, leftValue: null }];
+  let prevValue: string = null;
+  return result.reduce(
+    (acc, range, idx) => {
+      const { leftType, leftValue, rightType, rightValue } = range;
+
+      if (idx === 0 && leftValue === '') {
+        if (leftType === EXCLUDING_POINT && isVersion(rightValue)) {
+          prevValue = rightValue;
+          return [...acc, { ...range, leftValue: null }];
+        }
+        return null;
       }
-      return null;
-    }
-    if (idx === lastIdx && rightValue === '') {
-      if (rightType === EXCLUDING_POINT && isVersion(leftValue)) {
+      if (idx === lastIdx && rightValue === '') {
+        if (rightType === EXCLUDING_POINT && isVersion(leftValue)) {
+          if (prevValue && compare(prevValue, leftValue) === 1) return null;
+          return [...acc, { ...range, rightValue: null }];
+        }
+        return null;
+      }
+      if (isVersion(leftValue) && isVersion(rightValue)) {
+        if (compare(leftValue, rightValue) === 1) return null;
         if (prevValue && compare(prevValue, leftValue) === 1) return null;
-        return [...acc, { ...range, rightValue: null }];
+        prevValue = rightValue;
+        return [...acc, range];
       }
       return null;
-    }
-    if (isVersion(leftValue) && isVersion(rightValue)) {
-      if (compare(leftValue, rightValue) === 1) return null;
-      if (prevValue && compare(prevValue, leftValue) === 1) return null;
-      prevValue = rightValue;
-      return [...acc, range];
-    }
-    return null;
-  }, []);
+    },
+    [] as Range[]
+  );
 }
 
-function rangeToStr(fullRange) {
+function rangeToStr(fullRange: Range[]) {
   if (fullRange === null) return null;
 
-  const valToStr = val => (val === null ? '' : val);
+  const valToStr = (val: string) => (val === null ? '' : val);
 
   if (fullRange.length === 1) {
     const { leftBracket, rightBracket, leftValue, rightValue } = fullRange[0];
@@ -362,10 +398,10 @@ function rangeToStr(fullRange) {
   return intervals.join(',');
 }
 
-function autoExtendMavenRange(currentRepresentation, newValue) {
+function autoExtendMavenRange(currentRepresentation: string, newValue: string) {
   const range = parseRange(currentRepresentation);
   if (!range) return currentRepresentation;
-  const isPoint = vals => {
+  const isPoint = (vals: Range[]) => {
     if (vals.length !== 1) return false;
     const { leftType, leftValue, rightType, rightValue } = vals[0];
     return (
@@ -402,7 +438,7 @@ function autoExtendMavenRange(currentRepresentation, newValue) {
   return rangeToStr(range);
 }
 
-function isSubversion(majorVersion, minorVersion) {
+function isSubversion(majorVersion: string, minorVersion: string) {
   const majorTokens = tokenize(majorVersion);
   const minorTokens = tokenize(minorVersion);
 
@@ -420,7 +456,7 @@ function isSubversion(majorVersion, minorVersion) {
   return result;
 }
 
-module.exports = {
+export {
   PREFIX_DOT,
   PREFIX_HYPHEN,
   TYPE_NUMBER,
@@ -429,7 +465,7 @@ module.exports = {
   isSubversion,
   compare,
   isVersion,
-  isSingleVersion: isVersion,
+  isVersion as isSingleVersion,
   isValid,
   parseRange,
   rangeToStr,
diff --git a/lib/versioning/maven/index.js b/lib/versioning/maven/index.ts
similarity index 70%
rename from lib/versioning/maven/index.js
rename to lib/versioning/maven/index.ts
index 1ef505e3557414dd3dac14300f51cf4773e0cfbe..214271c76912043c86c3ae2c34a0c1e4fe43b1b3 100644
--- a/lib/versioning/maven/index.js
+++ b/lib/versioning/maven/index.ts
@@ -1,4 +1,4 @@
-const {
+import {
   isVersion,
   isValid,
   tokenize,
@@ -9,11 +9,12 @@ const {
   autoExtendMavenRange,
   parseRange,
   EXCLUDING_POINT,
-} = require('./compare');
+} from './compare';
+import { RangeStrategy, VersioningApi } from '../common';
 
-const equals = (a, b) => compare(a, b) === 0;
+const equals = (a: string, b: string) => compare(a, b) === 0;
 
-function matches(a, b) {
+function matches(a: string, b: string) {
   if (!b) return false;
   if (isVersion(b)) return equals(a, b);
   const ranges = parseRange(b);
@@ -44,28 +45,28 @@ function matches(a, b) {
   }, false);
 }
 
-const getMajor = version => {
+const getMajor = (version: string) => {
   if (isVersion(version)) {
     const tokens = tokenize(version);
     const majorToken = tokens[0];
-    return majorToken.val;
+    return +majorToken.val;
   }
   return null;
 };
 
-const getMinor = version => {
+const getMinor = (version: string) => {
   if (isVersion(version)) {
     const tokens = tokenize(version);
     const minorToken = tokens[1];
     if (minorToken && minorToken.type === TYPE_NUMBER) {
-      return minorToken.val;
+      return +minorToken.val;
     }
     return 0;
   }
   return null;
 };
 
-const getPatch = version => {
+const getPatch = (version: string) => {
   if (isVersion(version)) {
     const tokens = tokenize(version);
     const minorToken = tokens[1];
@@ -75,26 +76,26 @@ const getPatch = version => {
       minorToken.type === TYPE_NUMBER &&
       patchToken.type === TYPE_NUMBER
     ) {
-      return patchToken.val;
+      return +patchToken.val;
     }
     return 0;
   }
   return null;
 };
 
-const isGreaterThan = (a, b) => compare(a, b) === 1;
+const isGreaterThan = (a: string, b: string) => compare(a, b) === 1;
 
-const isStable = version => {
+const isStable = (version: string) => {
   if (isVersion(version)) {
     const tokens = tokenize(version);
     const qualToken = tokens.find(token => token.type === TYPE_QUALIFIER);
     if (qualToken) {
       const val = qualToken.val;
-      if (val === 'final') return true;
-      if (val === 'ga') return true;
-      if (val === 'release') return true;
-      if (val === 'sp') return true;
-      // istanbul ignore next
+      // TODO: Can this if be removed, we never get here
+      // istanbul ignore if
+      if (val === 'final' || val === 'ga') return true;
+
+      if (val === 'release' || val === 'sp') return true;
       return false;
     }
     return true;
@@ -102,7 +103,7 @@ const isStable = version => {
   return null;
 };
 
-const maxSatisfyingVersion = (versions, range) => {
+const maxSatisfyingVersion = (versions: string[], range: string) => {
   return versions.reduce((result, version) => {
     if (matches(version, range)) {
       if (!result) return version;
@@ -112,14 +113,21 @@ const maxSatisfyingVersion = (versions, range) => {
   }, null);
 };
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  _fromVersion: string,
+  toVersion: string
+) {
   if (isVersion(currentValue) || rangeStrategy === 'pin') {
     return toVersion;
   }
   return autoExtendMavenRange(currentValue, toVersion);
 }
 
-module.exports = {
+export { isValid };
+
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -136,3 +144,5 @@ module.exports = {
   getNewValue,
   sortVersions: compare,
 };
+
+export default api;
diff --git a/lib/versioning/node/index.js b/lib/versioning/node/index.js
deleted file mode 100644
index b6d025ef9a755f3bc9262af2b93e57f451bfedb7..0000000000000000000000000000000000000000
--- a/lib/versioning/node/index.js
+++ /dev/null
@@ -1,20 +0,0 @@
-const npm = require('../npm');
-
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
-  const res = npm.getNewValue(
-    currentValue,
-    rangeStrategy,
-    fromVersion,
-    toVersion
-  );
-  if (npm.isVersion(res)) {
-    // normalize out any 'v' prefix
-    return npm.isVersion(res);
-  }
-  return res;
-}
-
-module.exports = {
-  ...npm,
-  getNewValue,
-};
diff --git a/lib/versioning/node/index.ts b/lib/versioning/node/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..6a150c5bbf13ad331b5d20181a229029941cb46c
--- /dev/null
+++ b/lib/versioning/node/index.ts
@@ -0,0 +1,29 @@
+import npm, { isVersion, isValid } from '../npm';
+import { RangeStrategy, VersioningApi } from '../common';
+
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
+  const res = npm.getNewValue(
+    currentValue,
+    rangeStrategy,
+    fromVersion,
+    toVersion
+  );
+  if (isVersion(res)) {
+    // normalize out any 'v' prefix
+    return isVersion(res);
+  }
+  return res;
+}
+
+export { isValid };
+
+export const api: VersioningApi = {
+  ...npm,
+  getNewValue,
+};
+export default api;
diff --git a/lib/versioning/npm/index.js b/lib/versioning/npm/index.ts
similarity index 64%
rename from lib/versioning/npm/index.js
rename to lib/versioning/npm/index.ts
index 3c6cf9af120e25c4fcb717f00002ed079f35e967..7f60432699718b3e9a8e7fe279770480b46611fd 100644
--- a/lib/versioning/npm/index.js
+++ b/lib/versioning/npm/index.ts
@@ -1,8 +1,7 @@
-const semver = require('semver');
-const stable = require('semver-stable');
-const { getNewValue } = require('./range');
-
-const { is: isStable } = stable;
+import * as semver from 'semver';
+import { is as isStable } from 'semver-stable';
+import { getNewValue } from './range';
+import { VersioningApi } from '../common';
 
 const {
   compare: sortVersions,
@@ -20,14 +19,14 @@ const {
 } = semver;
 
 // If this is left as an alias, inputs like "17.04.0" throw errors
-const isValid = input => validRange(input);
-const isVersion = input => valid(input);
+export const isValid = (input: string) => validRange(input);
+export const isVersion = (input: string) => valid(input);
 
-const isSingleVersion = constraint =>
+const isSingleVersion = (constraint: string) =>
   isVersion(constraint) ||
   (constraint.startsWith('=') && isVersion(constraint.substring(1).trim()));
 
-module.exports = {
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -45,3 +44,5 @@ module.exports = {
   minSatisfyingVersion,
   sortVersions,
 };
+
+export default api;
diff --git a/lib/versioning/npm/range.js b/lib/versioning/npm/range.ts
similarity index 93%
rename from lib/versioning/npm/range.js
rename to lib/versioning/npm/range.ts
index adfd7591c3ca059169ee03ef1e8ba67cad8399b4..4bf0bef94b885a8042af7a95966ab1e8a3c6ac2c 100644
--- a/lib/versioning/npm/range.js
+++ b/lib/versioning/npm/range.ts
@@ -1,20 +1,24 @@
-const {
-  inc: increment,
+import {
+  inc as increment,
   major,
   minor,
   patch,
   prerelease,
   satisfies,
-  valid: isVersion,
-} = require('semver');
-const { parseRange } = require('semver-utils');
-const { logger } = require('../../logger');
+  valid as isVersion,
+} from 'semver';
+import { parseRange } from 'semver-utils';
+import { logger } from '../../logger';
+import { RangeStrategy } from '../common';
 
-module.exports = {
-  getNewValue,
-};
+export { getNewValue };
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   if (rangeStrategy === 'pin' || isVersion(currentValue)) {
     return toVersion;
   }
diff --git a/lib/versioning/pep440/index.js b/lib/versioning/pep440/index.ts
similarity index 63%
rename from lib/versioning/pep440/index.js
rename to lib/versioning/pep440/index.ts
index 9b128f514ee4c5519583c687d482c8468a538839..699fe4a48b6fb4a0d20b6786bcd76103196c9124 100644
--- a/lib/versioning/pep440/index.js
+++ b/lib/versioning/pep440/index.ts
@@ -1,6 +1,7 @@
-const pep440 = require('@renovate/pep440');
-const { filter } = require('@renovate/pep440/lib/specifier');
-const { getNewValue } = require('./range');
+import * as pep440 from '@renovate/pep440';
+import { filter } from '@renovate/pep440/lib/specifier';
+import { getNewValue } from './range';
+import { VersioningApi } from '../common';
 
 const {
   compare: sortVersions,
@@ -15,7 +16,7 @@ const {
   eq: equals,
 } = pep440;
 
-const isStable = input => {
+const isStable = (input: string) => {
   const version = explain(input);
   if (!version) {
     return false;
@@ -24,23 +25,25 @@ const isStable = input => {
 };
 
 // If this is left as an alias, inputs like "17.04.0" throw errors
-const isValid = input => validRange(input);
+export const isValid = (input: string) => validRange(input);
 
-const maxSatisfyingVersion = (versions, range) => {
+const maxSatisfyingVersion = (versions: string[], range: string) => {
   const found = filter(versions, range).sort(sortVersions);
   return found.length === 0 ? null : found[found.length - 1];
 };
 
-const minSatisfyingVersion = (versions, range) => {
+const minSatisfyingVersion = (versions: string[], range: string) => {
   const found = filter(versions, range).sort(sortVersions);
   return found.length === 0 ? null : found[0];
 };
 
-const isSingleVersion = constraint =>
+export const isSingleVersion = (constraint: string) =>
   isVersion(constraint) ||
   (constraint.startsWith('==') && isVersion(constraint.substring(2).trim()));
 
-module.exports = {
+export { matches };
+
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -57,3 +60,5 @@ module.exports = {
   getNewValue,
   sortVersions,
 };
+
+export default api;
diff --git a/lib/versioning/pep440/range.js b/lib/versioning/pep440/range.ts
similarity index 81%
rename from lib/versioning/pep440/range.js
rename to lib/versioning/pep440/range.ts
index 6d78fe39209d7bd601e044dbec3944ce78827865..0526b336b8a2e95b88ddfa4dffb32064af380deb 100644
--- a/lib/versioning/pep440/range.js
+++ b/lib/versioning/pep440/range.ts
@@ -1,16 +1,18 @@
-const { gte, lte, satisfies } = require('@renovate/pep440');
+import { gte, lte, satisfies } from '@renovate/pep440';
+import { parse as parseVersion } from '@renovate/pep440/lib/version';
+import { parse as parseRange } from '@renovate/pep440/lib/specifier';
+import { logger } from '../../logger';
+import { RangeStrategy } from '../common';
 
-const { parse: parseVersion } = require('@renovate/pep440/lib/version');
-const { parse: parseRange } = require('@renovate/pep440/lib/specifier');
-const { logger } = require('../../logger');
+export { getNewValue };
 
-module.exports = {
-  getNewValue,
-};
-
-function getFutureVersion(baseVersion, toVersion, step) {
-  const toRelease = parseVersion(toVersion).release;
-  const baseRelease = parseVersion(baseVersion).release;
+function getFutureVersion(
+  baseVersion: string,
+  toVersion: string,
+  step: number
+) {
+  const toRelease: number[] = parseVersion(toVersion).release;
+  const baseRelease: number[] = parseVersion(baseVersion).release;
   let found = false;
   const futureRelease = baseRelease.map((basePart, index) => {
     if (found) {
@@ -29,12 +31,23 @@ function getFutureVersion(baseVersion, toVersion, step) {
   return futureRelease.join('.');
 }
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+interface Range {
+  operator: string;
+  prefix: string;
+  version: string;
+}
+
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   // easy pin
   if (rangeStrategy === 'pin') {
     return '==' + toVersion;
   }
-  const ranges = parseRange(currentValue);
+  const ranges: Range[] = parseRange(currentValue);
   if (!ranges) {
     logger.warn('Invalid currentValue: ' + currentValue);
     return null;
diff --git a/lib/versioning/poetry/index.js b/lib/versioning/poetry/index.ts
similarity index 70%
rename from lib/versioning/poetry/index.js
rename to lib/versioning/poetry/index.ts
index b073703b95dbd7d172cd14c7a945e41362508827..5ca4e130c1142b0278f3dc183974b980606eab9c 100644
--- a/lib/versioning/poetry/index.js
+++ b/lib/versioning/poetry/index.ts
@@ -1,15 +1,16 @@
-const { parseRange } = require('semver-utils');
-const { major, minor } = require('semver');
-const npm = require('../npm');
+import { parseRange } from 'semver-utils';
+import { major, minor } from 'semver';
+import { api as npm } from '../npm';
+import { RangeStrategy, VersioningApi } from '../common';
 
-function notEmpty(s) {
+function notEmpty(s: string) {
   return s !== '';
 }
 
 // This function works like cargo2npm, but it doesn't
 // add a '^', because poetry treats versions without operators as
 // exact versions.
-function poetry2npm(input) {
+function poetry2npm(input: string) {
   const versions = input
     .split(',')
     .map(str => str.trim())
@@ -20,7 +21,7 @@ function poetry2npm(input) {
 // NOTE: This function is copied from cargo versionsing code.
 // Poetry uses commas (like in cargo) instead of spaces (like in npm)
 // for AND operation.
-function npm2poetry(input) {
+function npm2poetry(input: string) {
   // Note: this doesn't remove the ^
   const res = input
     .split(' ')
@@ -36,22 +37,22 @@ function npm2poetry(input) {
   return res.join(', ');
 }
 
-const isLessThanRange = (version, range) =>
+const isLessThanRange = (version: string, range: string) =>
   npm.isLessThanRange(version, poetry2npm(range));
 
-const isValid = input => npm.isValid(poetry2npm(input));
+export const isValid = (input: string) => npm.isValid(poetry2npm(input));
 
-const isVersion = input => npm.isVersion(input);
+const isVersion = (input: string) => npm.isVersion(input);
+const matches = (version: string, range: string) =>
+  npm.matches(version, poetry2npm(range));
 
-const matches = (version, range) => npm.matches(version, poetry2npm(range));
-
-const maxSatisfyingVersion = (versions, range) =>
+const maxSatisfyingVersion = (versions: string[], range: string) =>
   npm.maxSatisfyingVersion(versions, poetry2npm(range));
 
-const minSatisfyingVersion = (versions, range) =>
+const minSatisfyingVersion = (versions: string[], range: string) =>
   npm.minSatisfyingVersion(versions, poetry2npm(range));
 
-const isSingleVersion = constraint =>
+const isSingleVersion = (constraint: string) =>
   (constraint.trim().startsWith('=') &&
     isVersion(
       constraint
@@ -61,7 +62,12 @@ const isSingleVersion = constraint =>
     )) ||
   isVersion(constraint.trim());
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  fromVersion: string,
+  toVersion: string
+) {
   if (rangeStrategy === 'replace') {
     const npmCurrentValue = poetry2npm(currentValue);
     const parsedRange = parseRange(npmCurrentValue);
@@ -91,7 +97,11 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   return newPoetry;
 }
 
-function handleShort(operator, currentValue, toVersion) {
+function handleShort(
+  operator: string,
+  currentValue: string,
+  toVersion: string
+) {
   const toVersionMajor = major(toVersion);
   const toVersionMinor = minor(toVersion);
   const split = currentValue.split('.');
@@ -106,7 +116,7 @@ function handleShort(operator, currentValue, toVersion) {
   return null;
 }
 
-module.exports = {
+export const api: VersioningApi = {
   ...npm,
   getNewValue,
   isLessThanRange,
@@ -116,3 +126,4 @@ module.exports = {
   maxSatisfyingVersion,
   minSatisfyingVersion,
 };
+export default api;
diff --git a/lib/versioning/ruby/index.js b/lib/versioning/ruby/index.js
deleted file mode 100644
index 36036c9d4d8afa1969083b34511d762b94fd8645..0000000000000000000000000000000000000000
--- a/lib/versioning/ruby/index.js
+++ /dev/null
@@ -1,88 +0,0 @@
-const {
-  eq,
-  valid,
-  gt,
-  satisfies,
-  maxSatisfying,
-  minSatisfying,
-} = require('@snyk/ruby-semver');
-const { logger } = require('../../logger');
-const { parse: parseVersion } = require('./version');
-const { parse: parseRange, ltr } = require('./range');
-const { isSingleOperator, isValidOperator } = require('./operator');
-const { pin, bump, replace } = require('./strategies');
-
-const equals = (left, right) => eq(left, right);
-
-const getMajor = version => parseVersion(version).major;
-const getMinor = version => parseVersion(version).minor;
-const getPatch = version => parseVersion(version).patch;
-
-const isVersion = version => !!valid(version);
-const isGreaterThan = (left, right) => gt(left, right);
-const isLessThanRange = (version, range) => ltr(version, range);
-
-const isSingleVersion = range => {
-  const { version, operator } = parseRange(range);
-
-  return operator
-    ? isVersion(version) && isSingleOperator(operator)
-    : isVersion(version);
-};
-
-const isStable = version =>
-  parseVersion(version).prerelease ? false : isVersion(version);
-
-const isValid = input =>
-  input
-    .split(',')
-    .map(piece => piece.trim())
-    .every(range => {
-      const { version, operator } = parseRange(range);
-
-      return operator
-        ? isVersion(version) && isValidOperator(operator)
-        : isVersion(version);
-    });
-
-const matches = (version, range) => satisfies(version, range);
-const maxSatisfyingVersion = (versions, range) =>
-  maxSatisfying(versions, range);
-const minSatisfyingVersion = (versions, range) =>
-  minSatisfying(versions, range);
-
-const getNewValue = (currentValue, rangeStrategy, fromVersion, toVersion) => {
-  switch (rangeStrategy) {
-    case 'pin':
-      return pin({ to: toVersion });
-    case 'bump':
-      return bump({ range: currentValue, to: toVersion });
-    case 'replace':
-      return replace({ range: currentValue, to: toVersion });
-    // istanbul ignore next
-    default:
-      logger.warn(`Unsupported strategy ${rangeStrategy}`);
-      return null;
-  }
-};
-
-const sortVersions = (left, right) => (gt(left, right) ? 1 : -1);
-
-module.exports = {
-  equals,
-  getMajor,
-  getMinor,
-  getPatch,
-  isCompatible: isVersion,
-  isGreaterThan,
-  isLessThanRange,
-  isSingleVersion,
-  isStable,
-  isValid,
-  isVersion,
-  matches,
-  maxSatisfyingVersion,
-  minSatisfyingVersion,
-  getNewValue,
-  sortVersions,
-};
diff --git a/lib/versioning/ruby/index.ts b/lib/versioning/ruby/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..01c230b26bba6d4013fb13fd9be4552256fe8f5c
--- /dev/null
+++ b/lib/versioning/ruby/index.ts
@@ -0,0 +1,97 @@
+import {
+  eq,
+  valid,
+  gt,
+  satisfies,
+  maxSatisfying,
+  minSatisfying,
+} from '@snyk/ruby-semver';
+import { VersioningApi, RangeStrategy } from '../common';
+import { logger } from '../../logger';
+import { parse as parseVersion } from './version';
+import { parse as parseRange, ltr } from './range';
+import { isSingleOperator, isValidOperator } from './operator';
+import { pin, bump, replace } from './strategies';
+
+const equals = (left: string, right: string) => eq(left, right);
+
+const getMajor = (version: string) => parseVersion(version).major;
+const getMinor = (version: string) => parseVersion(version).minor;
+const getPatch = (version: string) => parseVersion(version).patch;
+
+export const isVersion = (version: string) => !!valid(version);
+const isGreaterThan = (left: string, right: string) => gt(left, right);
+const isLessThanRange = (version: string, range: string) => ltr(version, range);
+
+const isSingleVersion = (range: string) => {
+  const { version, operator } = parseRange(range);
+
+  return operator
+    ? isVersion(version) && isSingleOperator(operator)
+    : isVersion(version);
+};
+
+const isStable = (version: string) =>
+  parseVersion(version).prerelease ? false : isVersion(version);
+
+export const isValid = (input: string) =>
+  input
+    .split(',')
+    .map(piece => piece.trim())
+    .every(range => {
+      const { version, operator } = parseRange(range);
+
+      return operator
+        ? isVersion(version) && isValidOperator(operator)
+        : isVersion(version);
+    });
+
+export const matches = (version: string, range: string) =>
+  satisfies(version, range);
+const maxSatisfyingVersion = (versions: string[], range: string) =>
+  maxSatisfying(versions, range);
+const minSatisfyingVersion = (versions: string[], range: string) =>
+  minSatisfying(versions, range);
+
+const getNewValue = (
+  currentValue: string,
+  rangeStrategy: RangeStrategy,
+  _fromVersion: string,
+  toVersion: string
+) => {
+  switch (rangeStrategy) {
+    case 'pin':
+      return pin({ to: toVersion });
+    case 'bump':
+      return bump({ range: currentValue, to: toVersion });
+    case 'replace':
+      return replace({ range: currentValue, to: toVersion });
+    // istanbul ignore next
+    default:
+      logger.warn(`Unsupported strategy ${rangeStrategy}`);
+      return null;
+  }
+};
+
+export const sortVersions = (left: string, right: string) =>
+  gt(left, right) ? 1 : -1;
+
+export const api: VersioningApi = {
+  equals,
+  getMajor,
+  getMinor,
+  getPatch,
+  isCompatible: isVersion,
+  isGreaterThan,
+  isLessThanRange,
+  isSingleVersion,
+  isStable,
+  isValid,
+  isVersion,
+  matches,
+  maxSatisfyingVersion,
+  minSatisfyingVersion,
+  getNewValue,
+  sortVersions,
+};
+export default api;
diff --git a/lib/versioning/ruby/operator.js b/lib/versioning/ruby/operator.ts
similarity index 67%
rename from lib/versioning/ruby/operator.js
rename to lib/versioning/ruby/operator.ts
index 9a85b898bac58a1e12f06411e1e7c55aa6aecd7a..05e32a35e5beb5c1d3dd261bda448e42dc39e22a 100644
--- a/lib/versioning/ruby/operator.js
+++ b/lib/versioning/ruby/operator.ts
@@ -11,10 +11,10 @@ const PGTE = '~>';
 const SINGLE = [EQUAL];
 const ALL = [EQUAL, NOT_EQUAL, GT, LT, GTE, LTE, PGTE];
 
-const isValidOperator = operator => ALL.includes(operator);
-const isSingleOperator = operator => SINGLE.includes(operator);
+const isValidOperator = (operator: string) => ALL.includes(operator);
+const isSingleOperator = (operator: string) => SINGLE.includes(operator);
 
-module.exports = {
+export {
   EQUAL,
   NOT_EQUAL,
   GT,
diff --git a/lib/versioning/ruby/range.js b/lib/versioning/ruby/range.ts
similarity index 54%
rename from lib/versioning/ruby/range.js
rename to lib/versioning/ruby/range.ts
index bfcc1fcb2f4578c95768867eff7e9b8fba1230d1..e2f161f0e6daf5d020c4e53c0a94c1187c7fea4e 100644
--- a/lib/versioning/ruby/range.js
+++ b/lib/versioning/ruby/range.ts
@@ -1,9 +1,14 @@
-const GemVersion = require('@snyk/ruby-semver/lib/ruby/gem-version');
-const GemRequirement = require('@snyk/ruby-semver/lib/ruby/gem-requirement');
-const { logger } = require('../../logger');
-const { EQUAL, NOT_EQUAL, GT, LT, GTE, LTE, PGTE } = require('./operator');
+import { create } from '@snyk/ruby-semver/lib/ruby/gem-version';
+import { parse as _parse } from '@snyk/ruby-semver/lib/ruby/gem-requirement';
+import { logger } from '../../logger';
+import { EQUAL, NOT_EQUAL, GT, LT, GTE, LTE, PGTE } from './operator';
 
-const parse = range => {
+export interface Range {
+  version: string;
+  operator: string;
+}
+
+const parse = (range: string): Range => {
   const regExp = /^([^\d\s]+)?\s?([0-9a-zA-Z-.-]+)$/g;
 
   const value = (range || '').trim();
@@ -15,9 +20,16 @@ const parse = range => {
   };
 };
 
-const ltr = (version, range) => {
-  const gemVersion = GemVersion.create(version);
-  const requirements = range.split(',').map(GemRequirement.parse);
+interface GemVersion {
+  release(): GemVersion;
+  compare(ver: GemVersion): number;
+  bump(): GemVersion;
+}
+type GemRequirement = [string, GemVersion];
+
+const ltr = (version: string, range: string) => {
+  const gemVersion: GemVersion = create(version);
+  const requirements: GemRequirement[] = range.split(',').map(_parse);
 
   const results = requirements.map(([operator, ver]) => {
     switch (operator) {
@@ -44,7 +56,4 @@ const ltr = (version, range) => {
   return results.reduce((accumulator, value) => accumulator && value, true);
 };
 
-module.exports = {
-  parse,
-  ltr,
-};
+export { parse, ltr };
diff --git a/lib/versioning/ruby/strategies/bump.js b/lib/versioning/ruby/strategies/bump.ts
similarity index 68%
rename from lib/versioning/ruby/strategies/bump.js
rename to lib/versioning/ruby/strategies/bump.ts
index 39b2549cd00703777967e0e835a084a72e185d31..723adedda7f1191db821b6e88e68f1e9a12c24f6 100644
--- a/lib/versioning/ruby/strategies/bump.js
+++ b/lib/versioning/ruby/strategies/bump.ts
@@ -1,10 +1,10 @@
-const { gte, lte } = require('@snyk/ruby-semver');
-const { logger } = require('../../../logger');
-const { EQUAL, NOT_EQUAL, GT, LT, GTE, LTE, PGTE } = require('../operator');
-const { floor, increment, decrement } = require('../version');
-const { parse: parseRange } = require('../range');
+import { gte, lte } from '@snyk/ruby-semver';
+import { logger } from '../../../logger';
+import { EQUAL, NOT_EQUAL, GT, LT, GTE, LTE, PGTE } from '../operator';
+import { floor, increment, decrement } from '../version';
+import { parse as parseRange } from '../range';
 
-module.exports = ({ range, to }) => {
+export default ({ range, to }: { range: string; to: string }) => {
   const ranges = range.split(',').map(parseRange);
   const results = ranges.map(({ operator, version: ver }) => {
     switch (operator) {
diff --git a/lib/versioning/ruby/strategies/index.js b/lib/versioning/ruby/strategies/index.js
deleted file mode 100644
index a1bc4517ce57a63be970a010f13af6a44b83d18e..0000000000000000000000000000000000000000
--- a/lib/versioning/ruby/strategies/index.js
+++ /dev/null
@@ -1,9 +0,0 @@
-const pin = require('./pin');
-const bump = require('./bump');
-const replace = require('./replace');
-
-module.exports = {
-  pin,
-  bump,
-  replace,
-};
diff --git a/lib/versioning/ruby/strategies/index.ts b/lib/versioning/ruby/strategies/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..8a6736d5fd278ec9a770e342093f36db67fa8e76
--- /dev/null
+++ b/lib/versioning/ruby/strategies/index.ts
@@ -0,0 +1,5 @@
+import pin from './pin';
+import bump from './bump';
+import replace from './replace';
+
+export { pin, bump, replace };
diff --git a/lib/versioning/ruby/strategies/pin.js b/lib/versioning/ruby/strategies/pin.js
deleted file mode 100644
index 071862075c515995e6063bbaf1908249bea249ce..0000000000000000000000000000000000000000
--- a/lib/versioning/ruby/strategies/pin.js
+++ /dev/null
@@ -1 +0,0 @@
-module.exports = ({ to }) => to;
diff --git a/lib/versioning/ruby/strategies/pin.ts b/lib/versioning/ruby/strategies/pin.ts
new file mode 100644
index 0000000000000000000000000000000000000000..279563363617c24ceca21ebb980994a79f2fb440
--- /dev/null
+++ b/lib/versioning/ruby/strategies/pin.ts
@@ -0,0 +1 @@
+export default ({ to }: { to: string }) => to;
diff --git a/lib/versioning/ruby/strategies/replace.js b/lib/versioning/ruby/strategies/replace.ts
similarity index 65%
rename from lib/versioning/ruby/strategies/replace.js
rename to lib/versioning/ruby/strategies/replace.ts
index 091013e39650a83479af173db2c699576a764651..927c9a7b1d8aab3cd238837c76b2645255384ccb 100644
--- a/lib/versioning/ruby/strategies/replace.js
+++ b/lib/versioning/ruby/strategies/replace.ts
@@ -1,7 +1,7 @@
-const { satisfies } = require('@snyk/ruby-semver');
-const bump = require('./bump');
+import { satisfies } from '@snyk/ruby-semver';
+import bump from './bump';
 
-module.exports = ({ to, range }) => {
+export default ({ to, range }: { range: string; to: string }) => {
   if (satisfies(to, range)) {
     return range;
   }
diff --git a/lib/versioning/ruby/version.js b/lib/versioning/ruby/version.ts
similarity index 59%
rename from lib/versioning/ruby/version.js
rename to lib/versioning/ruby/version.ts
index 5e3c2ff93dc5898d97051ca9e3f3b23f9f3eafd3..e46d249b0af6e8fe537295cfc3a76cd5d4de82aa 100644
--- a/lib/versioning/ruby/version.js
+++ b/lib/versioning/ruby/version.ts
@@ -1,23 +1,30 @@
-const last = require('lodash/last');
-const GemVersion = require('@snyk/ruby-semver/lib/ruby/gem-version');
-const { diff, major, minor, patch, prerelease } = require('@snyk/ruby-semver');
-
-const parse = version => ({
+import last from 'lodash/last';
+import { create } from '@snyk/ruby-semver/lib/ruby/gem-version';
+import { diff, major, minor, patch, prerelease } from '@snyk/ruby-semver';
+
+interface RubyVersion {
+  major: number;
+  minor: number;
+  patch: number;
+  prerelease: string[];
+}
+
+const parse = (version: string): RubyVersion => ({
   major: major(version),
   minor: minor(version),
   patch: patch(version),
   prerelease: prerelease(version),
 });
 
-const adapt = (left, right) =>
+const adapt = (left: string, right: string) =>
   left
     .split('.')
     .slice(0, right.split('.').length)
     .join('.');
 
-const floor = version =>
+const floor = (version: string) =>
   [
-    ...GemVersion.create(version)
+    ...create(version)
       .release()
       .getSegments()
       .slice(0, -1),
@@ -25,8 +32,8 @@ const floor = version =>
   ].join('.');
 
 // istanbul ignore next
-const incrementLastSegment = version => {
-  const segments = GemVersion.create(version)
+const incrementLastSegment = (version: string) => {
+  const segments = create(version)
     .release()
     .getSegments();
   const nextLast = parseInt(last(segments), 10) + 1;
@@ -35,21 +42,26 @@ const incrementLastSegment = version => {
 };
 
 // istanbul ignore next
-const incrementMajor = (maj, min, ptch, pre) =>
-  min === 0 || ptch === 0 || pre.length === 0 ? maj + 1 : maj;
+const incrementMajor = (
+  maj: number,
+  min: number,
+  ptch: number,
+  pre: string[]
+) => (min === 0 || ptch === 0 || pre.length === 0 ? maj + 1 : maj);
 
 // istanbul ignore next
-const incrementMinor = (min, ptch, pre) =>
+const incrementMinor = (min: number, ptch: number, pre: string[]) =>
   ptch === 0 || pre.length === 0 ? min + 1 : min;
 
 // istanbul ignore next
-const incrementPatch = (ptch, pre) => (pre.length === 0 ? ptch + 1 : ptch);
+const incrementPatch = (ptch: number, pre: string[]) =>
+  pre.length === 0 ? ptch + 1 : ptch;
 
 // istanbul ignore next
-const increment = (from, to) => {
+const increment = (from: string, to: string): string => {
   const { major: maj, minor: min, patch: ptch, prerelease: pre } = parse(from);
 
-  let nextVersion;
+  let nextVersion: string;
   switch (diff(from, adapt(to, from))) {
     case 'major':
       nextVersion = [incrementMajor(maj, min, ptch, pre || []), 0, 0].join('.');
@@ -71,13 +83,13 @@ const increment = (from, to) => {
 };
 
 // istanbul ignore next
-const decrement = version => {
-  const segments = GemVersion.create(version)
+const decrement = (version: string): string => {
+  const segments = create(version)
     .release()
     .getSegments();
   const nextSegments = segments
     .reverse()
-    .reduce((accumulator, segment, index) => {
+    .reduce((accumulator: number[], segment: number, index: number) => {
       if (index === 0) {
         return [segment - 1];
       }
@@ -92,9 +104,4 @@ const decrement = version => {
   return nextSegments.reverse().join('.');
 };
 
-module.exports = {
-  parse,
-  floor,
-  increment,
-  decrement,
-};
+export { parse, floor, increment, decrement };
diff --git a/lib/versioning/semver/index.js b/lib/versioning/semver/index.ts
similarity index 61%
rename from lib/versioning/semver/index.js
rename to lib/versioning/semver/index.ts
index d702f9abc1490d40c56bc119d6292c65efcbd509..cadf2f520af4aead283d43f34b0a568808e2dd9c 100644
--- a/lib/versioning/semver/index.js
+++ b/lib/versioning/semver/index.ts
@@ -1,5 +1,6 @@
-const semver = require('semver');
-const stable = require('semver-stable');
+import semver from 'semver';
+import stable from 'semver-stable';
+import { RangeStrategy, VersioningApi } from '../common';
 
 const { is: isStable } = stable;
 
@@ -18,13 +19,20 @@ const {
 } = semver;
 
 // If this is left as an alias, inputs like "17.04.0" throw errors
-const isVersion = input => valid(input);
+export const isVersion = (input: string) => valid(input);
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+export { isVersion as isValid, maxSatisfyingVersion };
+
+function getNewValue(
+  _currentValue: string,
+  _rangeStrategy: RangeStrategy,
+  _fromVersion: string,
+  toVersion: string
+) {
   return toVersion;
 }
 
-module.exports = {
+export const api: VersioningApi = {
   equals,
   getMajor,
   getMinor,
@@ -42,3 +50,4 @@ module.exports = {
   getNewValue,
   sortVersions,
 };
+export default api;
diff --git a/lib/versioning/swift/index.js b/lib/versioning/swift/index.js
deleted file mode 100644
index 5d6934066cc9222fbba57a49c545755298ac705a..0000000000000000000000000000000000000000
--- a/lib/versioning/swift/index.js
+++ /dev/null
@@ -1,48 +0,0 @@
-const semver = require('semver');
-const stable = require('semver-stable');
-const { toSemverRange, getNewValue } = require('./range');
-
-const { is: isStable } = stable;
-
-const {
-  compare: sortVersions,
-  maxSatisfying,
-  minSatisfying,
-  major: getMajor,
-  minor: getMinor,
-  patch: getPatch,
-  satisfies,
-  valid,
-  validRange,
-  ltr,
-  gt: isGreaterThan,
-  eq: equals,
-} = semver;
-
-const isValid = input => !!valid(input) || !!validRange(toSemverRange(input));
-const isVersion = input => !!valid(input);
-const maxSatisfyingVersion = (versions, range) =>
-  maxSatisfying(versions, toSemverRange(range));
-const minSatisfyingVersion = (versions, range) =>
-  minSatisfying(versions, toSemverRange(range));
-const isLessThanRange = (version, range) => ltr(version, toSemverRange(range));
-const matches = (version, range) => satisfies(version, toSemverRange(range));
-
-module.exports = {
-  equals,
-  getMajor,
-  getMinor,
-  getNewValue,
-  getPatch,
-  isCompatible: isVersion,
-  isGreaterThan,
-  isLessThanRange,
-  isSingleVersion: isVersion,
-  isStable,
-  isValid,
-  isVersion,
-  matches,
-  maxSatisfyingVersion,
-  minSatisfyingVersion,
-  sortVersions,
-};
diff --git a/lib/versioning/swift/index.ts b/lib/versioning/swift/index.ts
new file mode 100644
index 0000000000000000000000000000000000000000..0f0df3a22646e5a52ee9fdac1e41edb7818174bc
--- /dev/null
+++ b/lib/versioning/swift/index.ts
@@ -0,0 +1,54 @@
+import semver from 'semver';
+import stable from 'semver-stable';
+import { toSemverRange, getNewValue } from './range';
+import { VersioningApi } from '../common';
+
+const { is: isStable } = stable;
+
+const {
+  compare: sortVersions,
+  maxSatisfying,
+  minSatisfying,
+  major: getMajor,
+  minor: getMinor,
+  patch: getPatch,
+  satisfies,
+  valid,
+  validRange,
+  ltr,
+  gt: isGreaterThan,
+  eq: equals,
+} = semver;
+
+export const isValid = (input: string) =>
+  !!valid(input) || !!validRange(toSemverRange(input));
+export const isVersion = (input: string) => !!valid(input);
+const maxSatisfyingVersion = (versions: string[], range: string) =>
+  maxSatisfying(versions, toSemverRange(range));
+const minSatisfyingVersion = (versions: string[], range: string) =>
+  minSatisfying(versions, toSemverRange(range));
+const isLessThanRange = (version: string, range: string) =>
+  ltr(version, toSemverRange(range));
+const matches = (version: string, range: string) =>
+  satisfies(version, toSemverRange(range));
+
+export const api: VersioningApi = {
+  equals,
+  getMajor,
+  getMinor,
+  getNewValue,
+  getPatch,
+  isCompatible: isVersion,
+  isGreaterThan,
+  isLessThanRange,
+  isSingleVersion: isVersion,
+  isStable,
+  isValid,
+  isVersion,
+  matches,
+  maxSatisfyingVersion,
+  minSatisfyingVersion,
+  sortVersions,
+};
+
+export default api;
diff --git a/lib/versioning/swift/range.js b/lib/versioning/swift/range.ts
similarity index 85%
rename from lib/versioning/swift/range.js
rename to lib/versioning/swift/range.ts
index 4b9e3f36b9743e1737f5d2ec0750c0f86a7bd14a..9552cf45758f60ab430d309ea6ed548566ffe23b 100644
--- a/lib/versioning/swift/range.js
+++ b/lib/versioning/swift/range.ts
@@ -1,11 +1,12 @@
-const semver = require('semver');
+import semver from 'semver';
+import { RangeStrategy } from '../common';
 
 const fromParam = /^\s*from\s*:\s*"([^"]+)"\s*$/;
 const fromRange = /^\s*"([^"]+)"\s*\.\.\.\s*$/;
 const binaryRange = /^\s*"([^"]+)"\s*(\.\.[.<])\s*"([^"]+)"\s*$/;
 const toRange = /^\s*(\.\.[.<])\s*"([^"]+)"\s*$/;
 
-function toSemverRange(range) {
+function toSemverRange(range: string) {
   if (fromParam.test(range)) {
     const [, version] = range.match(fromParam);
     if (semver.valid(version)) {
@@ -33,7 +34,12 @@ function toSemverRange(range) {
   return null;
 }
 
-function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
+function getNewValue(
+  currentValue: string,
+  _rangeStrategy: RangeStrategy,
+  _fromVersion: string,
+  toVersion: string
+) {
   if (fromParam.test(currentValue)) {
     return toVersion;
   }
@@ -52,7 +58,4 @@ function getNewValue(currentValue, rangeStrategy, fromVersion, toVersion) {
   return currentValue;
 }
 
-module.exports = {
-  toSemverRange,
-  getNewValue,
-};
+export { toSemverRange, getNewValue };
diff --git a/test/.eslintrc.js b/test/.eslintrc.js
index d0977a46a3276abb2fd3bd5141d7fcc6dcddfa64..ab1eca82ccbee6608ff40ca220237687f87007d6 100644
--- a/test/.eslintrc.js
+++ b/test/.eslintrc.js
@@ -8,7 +8,9 @@ module.exports = {
   rules: {
     'prefer-destructuring': 0,
     'prefer-promise-reject-errors': 0,
+    'import/no-dynamic-require': 0,
     'import/no-extraneous-dependencies': 0,
+    'import/no-named-as-default-member': 0,
     'global-require': 0,
   },
 };
diff --git a/test/versioning/__snapshots__/index.spec.ts.snap b/test/versioning/__snapshots__/index.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..17ac4c295a332306369cdb2674221eea49a6edfb
--- /dev/null
+++ b/test/versioning/__snapshots__/index.spec.ts.snap
@@ -0,0 +1,22 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`versioning.get(versionScheme) has api 1`] = `
+Array [
+  "equals",
+  "getMajor",
+  "getMinor",
+  "getNewValue",
+  "getPatch",
+  "isCompatible",
+  "isGreaterThan",
+  "isLessThanRange",
+  "isSingleVersion",
+  "isStable",
+  "isValid",
+  "isVersion",
+  "matches",
+  "maxSatisfyingVersion",
+  "minSatisfyingVersion",
+  "sortVersions",
+]
+`;
diff --git a/test/versioning/__snapshots__/loose.spec.ts.snap b/test/versioning/__snapshots__/loose.spec.ts.snap
new file mode 100644
index 0000000000000000000000000000000000000000..197f6bb52e49b9fd3ddde23d1075992639502f46
--- /dev/null
+++ b/test/versioning/__snapshots__/loose.spec.ts.snap
@@ -0,0 +1,7 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`loose. isVersion 1.1 1`] = `"1.1"`;
+
+exports[`loose. isVersion 1.3.RC2 1`] = `"1.3.RC2"`;
+
+exports[`loose. isVersion 2.1-rc2 1`] = `"2.1-rc2"`;
diff --git a/test/versioning/__snapshots__/ruby.spec.js.snap b/test/versioning/__snapshots__/ruby.spec.ts.snap
similarity index 100%
rename from test/versioning/__snapshots__/ruby.spec.js.snap
rename to test/versioning/__snapshots__/ruby.spec.ts.snap
diff --git a/test/versioning/cargo.spec.js b/test/versioning/cargo.spec.ts
similarity index 99%
rename from test/versioning/cargo.spec.js
rename to test/versioning/cargo.spec.ts
index d54a7790c14128fcde2ee2ca92072ae20bc091c5..a1a1524477da39c2d8df4bebc7c5e963a9fd405b 100644
--- a/test/versioning/cargo.spec.js
+++ b/test/versioning/cargo.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/cargo');
+import { api as semver } from '../../lib/versioning/cargo';
 
 describe('semver.matches()', () => {
   it('handles comma', () => {
diff --git a/test/versioning/composer.spec.js b/test/versioning/composer.spec.ts
similarity index 98%
rename from test/versioning/composer.spec.js
rename to test/versioning/composer.spec.ts
index 33932f5c938630478d1a3754790bdd06a6757eca..6cee2aebadc23300e05fbbb82e8a60bc60299cb9 100644
--- a/test/versioning/composer.spec.js
+++ b/test/versioning/composer.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/composer');
+import { api as semver } from '../../lib/versioning/composer';
 
 describe('semver.getPatch(input)', () => {
   it('gets patch', () => {
diff --git a/test/versioning/docker.spec.js b/test/versioning/docker.spec.ts
similarity index 97%
rename from test/versioning/docker.spec.js
rename to test/versioning/docker.spec.ts
index 345aa31c0b7b914c6494002f48aee8521da9de6d..0db20ffe5f65bbc963a02d894b1af563f41d140c 100644
--- a/test/versioning/docker.spec.js
+++ b/test/versioning/docker.spec.ts
@@ -1,6 +1,5 @@
-/** @type any */
-const docker = require('../../lib/versioning/docker');
-const semver = require('../../lib/versioning/semver');
+import docker from '../../lib/versioning/docker';
+import semver from '../../lib/versioning/semver';
 
 describe('docker.', () => {
   describe('isValid(version)', () => {
diff --git a/test/versioning/hashicorp.spec.js b/test/versioning/hashicorp.spec.ts
similarity index 96%
rename from test/versioning/hashicorp.spec.js
rename to test/versioning/hashicorp.spec.ts
index bdaac2550b41eafa5d541797cddb44e3a89aa286..72e6d50396abe4a3341bb5eb5d41ef808abab58e 100644
--- a/test/versioning/hashicorp.spec.js
+++ b/test/versioning/hashicorp.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/hashicorp');
+import { api as semver } from '../../lib/versioning/hashicorp';
 
 describe('semver.matches()', () => {
   it('handles tilde greater than', () => {
diff --git a/test/versioning/hex.spec.js b/test/versioning/hex.spec.ts
similarity index 98%
rename from test/versioning/hex.spec.js
rename to test/versioning/hex.spec.ts
index 8aca8e573e70ad7fd43285e80344e3bb4c4a79bc..c86d93f4e35db3fedf1860931c3a9af2e53c115e 100644
--- a/test/versioning/hex.spec.js
+++ b/test/versioning/hex.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/hex');
+import { api as semver } from '../../lib/versioning/hex';
 
 describe('lib/versioning/hex', () => {
   describe('semver.matches()', () => {
diff --git a/test/versioning/index.spec.js b/test/versioning/index.spec.js
deleted file mode 100644
index c2dc5c00cc68fdb28150e006c33d4520e3177ce8..0000000000000000000000000000000000000000
--- a/test/versioning/index.spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const versioning = require('../../lib/versioning');
-const supportedSchemes = require('../../lib/config/definitions')
-  .getOptions()
-  .find(option => option.name === 'versionScheme').allowedValues;
-
-describe('versioning.get(versionScheme)', () => {
-  it('should fallback to semver', () => {
-    expect(versioning.get(undefined)).toBe(versioning.get('semver'));
-    expect(versioning.get('unknown')).toBe(versioning.get('semver'));
-  });
-
-  it('should return the same interface', () => {
-    const optionalFunctions = ['isLessThanRange', 'valueToVersion'];
-    const npmApi = Object.keys(versioning.get('semver'))
-      .filter(val => !optionalFunctions.includes(val))
-      .sort();
-    for (const supportedScheme of supportedSchemes.filter(
-      scheme => scheme !== 'npm'
-    )) {
-      const schemeKeys = Object.keys(versioning.get(supportedScheme))
-        .filter(val => !optionalFunctions.includes(val))
-        .sort();
-      expect(schemeKeys).toEqual(npmApi);
-    }
-  });
-});
diff --git a/test/versioning/index.spec.ts b/test/versioning/index.spec.ts
new file mode 100644
index 0000000000000000000000000000000000000000..df061824e5aeb24b7adb328ec1137ccb36a9f95f
--- /dev/null
+++ b/test/versioning/index.spec.ts
@@ -0,0 +1,37 @@
+import * as versioning from '../../lib/versioning';
+import { getOptions } from '../../lib/config/definitions';
+
+const supportedSchemes = getOptions().find(
+  option => option.name === 'versionScheme'
+).allowedValues;
+
+describe('versioning.get(versionScheme)', () => {
+  it('has api', () => {
+    expect(Object.keys(versioning.get('semver')).sort()).toMatchSnapshot();
+  });
+
+  it('should fallback to semver', () => {
+    expect(versioning.get(undefined)).toBe(versioning.get('semver'));
+    expect(versioning.get('unknown')).toBe(versioning.get('semver'));
+  });
+
+  describe('should return the same interface', () => {
+    const optionalFunctions = ['isLessThanRange', 'valueToVersion'];
+    const npmApi = Object.keys(versioning.get('semver'))
+      .filter(val => !optionalFunctions.includes(val))
+      .sort();
+    for (const supportedScheme of supportedSchemes) {
+      it(supportedScheme, () => {
+        const schemeKeys = Object.keys(versioning.get(supportedScheme))
+          .filter(val => !optionalFunctions.includes(val))
+          .sort();
+        expect(schemeKeys).toEqual(npmApi);
+        expect(
+          Object.keys(
+            require('../../lib/versioning/' + supportedScheme).api
+          ).sort()
+        ).toEqual(Object.keys(versioning.get(supportedScheme)).sort());
+      });
+    }
+  });
+});
diff --git a/test/versioning/ivy.spec.js b/test/versioning/ivy.spec.ts
similarity index 97%
rename from test/versioning/ivy.spec.js
rename to test/versioning/ivy.spec.ts
index b9e86e05ce42d3389749f0019f0741b6dd710e18..23ebff9cfc09a67fdcb80e37847cb992ee724b5f 100644
--- a/test/versioning/ivy.spec.js
+++ b/test/versioning/ivy.spec.ts
@@ -1,11 +1,12 @@
-const {
+import {
   REV_TYPE_LATEST,
   REV_TYPE_SUBREV,
   REV_TYPE_RANGE,
   parseDynamicRevision,
-} = require('../../lib/versioning/ivy/parse');
+} from '../../lib/versioning/ivy/parse';
+import ivy from '../../lib/versioning/ivy';
 
-const { isVersion, matches } = require('../../lib/versioning/ivy/index');
+const { isVersion, matches } = ivy;
 
 describe('versioning/ivy/match', () => {
   it('parses dynamic revisions', () => {
diff --git a/test/versioning/loose.spec.js b/test/versioning/loose.spec.ts
similarity index 81%
rename from test/versioning/loose.spec.js
rename to test/versioning/loose.spec.ts
index 073a591b91cac841b449fd2a502e61f4a8575660..5b04940364582728e5d976ac389719722e6f1aa2 100644
--- a/test/versioning/loose.spec.js
+++ b/test/versioning/loose.spec.ts
@@ -1,6 +1,13 @@
-const loose = require('../../lib/versioning/loose');
+import loose from '../../lib/versioning/loose';
 
 describe('loose.', () => {
+  describe('isVersion', () => {
+    ['1.1', '1.3.RC2', '2.1-rc2'].forEach(version => {
+      it(version, () => {
+        expect(loose.isVersion(version)).toMatchSnapshot();
+      });
+    });
+  });
   describe('isValid(version)', () => {
     it('it must support varied precision, from 1 to 6 sections', () => {
       [
diff --git a/test/versioning/maven.spec.js b/test/versioning/maven.spec.ts
similarity index 93%
rename from test/versioning/maven.spec.js
rename to test/versioning/maven.spec.ts
index 9537ea58039c35c1a083ffdfcfae6966da946bcf..d82fd4b859463ee305ec1fc2f4a544cf99bbd6e9 100644
--- a/test/versioning/maven.spec.js
+++ b/test/versioning/maven.spec.ts
@@ -1,9 +1,11 @@
-const {
+import {
   compare,
   parseRange,
   rangeToStr,
   autoExtendMavenRange,
-} = require('../../lib/versioning/maven/compare');
+} from '../../lib/versioning/maven/compare';
+import maven from '../../lib/versioning/maven';
+
 const {
   isValid,
   isVersion,
@@ -13,7 +15,7 @@ const {
   getPatch,
   matches,
   getNewValue,
-} = require('../../lib/versioning/maven/index');
+} = maven;
 
 describe('versioning/maven/compare', () => {
   it('returns equality', () => {
@@ -251,7 +253,7 @@ describe('versioning/maven/index', () => {
   it('returns valid', () => {
     expect(isValid('1.0.0')).toBe(true);
     expect(isValid('[1.12.6,1.18.6]')).toBe(true);
-    expect(isValid()).toBe(false);
+    expect(isValid(undefined)).toBe(false);
   });
   it('validates version string', () => {
     expect(isVersion('')).toBe(false);
@@ -259,6 +261,7 @@ describe('versioning/maven/index', () => {
     expect(isVersion('0')).toBe(true);
     expect(isVersion('0.1-2-sp')).toBe(true);
     expect(isVersion('1-final')).toBe(true);
+    expect(isVersion('1-foo')).toBe(true);
     expect(isVersion('v1.0.0')).toBe(true);
     expect(isVersion('x1.0.0')).toBe(true);
     expect(isVersion('2.1.1.RELEASE')).toBe(true);
@@ -272,6 +275,7 @@ describe('versioning/maven/index', () => {
   it('checks if version is stable', () => {
     expect(isStable('')).toBeNull();
     expect(isStable('foobar')).toBe(false);
+    expect(isStable('final')).toBe(true);
     expect(isStable('1')).toBe(true);
     expect(isStable('1.2')).toBe(true);
     expect(isStable('1.2.3')).toBe(true);
@@ -279,6 +283,9 @@ describe('versioning/maven/index', () => {
     expect(isStable('v1.2.3.4')).toBe(true);
     expect(isStable('1-alpha-1')).toBe(false);
     expect(isStable('1-b1')).toBe(false);
+    expect(isStable('1-foo')).toBe(false);
+    expect(isStable('1-final-1.0.0')).toBe(true);
+    expect(isStable('1-release')).toBe(true);
     expect(isStable('1.final')).toBe(true);
     expect(isStable('1.0milestone1')).toBe(false);
     expect(isStable('1-sp')).toBe(true);
@@ -326,6 +333,16 @@ describe('versioning/maven/index', () => {
     expect(matches('1', '(0,1),(1,2)')).toBe(false);
     expect(matches('1.0.0.RC9.2', '(,1.0.0.RC9.2),(1.0.0.RC9.2,)')).toBe(false);
     expect(matches('1.0.0-RC14', '(,1.0.0.RC9.2),(1.0.0.RC9.2,)')).toBe(true);
+    expect(matches('0', '')).toBe(false);
+    expect(matches('1', '1')).toBe(true);
+    expect(matches('1', '(1')).toBe(false);
+  });
+
+  it('api', () => {
+    expect(maven.isGreaterThan('1.1', '1')).toBe(true);
+    expect(maven.maxSatisfyingVersion(['1'], '1')).toBe('1');
+    expect(maven.getNewValue('1', null, null, '1.1')).toBe('1.1');
+    expect(maven.getNewValue('[1.2.3,]', null, null, '1.2.4')).toBe('[1.2.3,]');
   });
   it('pins maven ranges', () => {
     const sample = [
diff --git a/test/versioning/node.spec.js b/test/versioning/node.spec.ts
similarity index 84%
rename from test/versioning/node.spec.js
rename to test/versioning/node.spec.ts
index e5ca0930a045a19a85417db9b315507f37657a18..22923ffa18017d8d3261524bb12987ad30a50f6e 100644
--- a/test/versioning/node.spec.js
+++ b/test/versioning/node.spec.ts
@@ -1,4 +1,4 @@
-const nodever = require('../../lib/versioning/node');
+import { api as nodever } from '../../lib/versioning/node';
 
 describe('semver.getNewValue()', () => {
   it('returns normalized toVersion', () => {
diff --git a/test/versioning/npm.spec.js b/test/versioning/npm.spec.ts
similarity index 98%
rename from test/versioning/npm.spec.js
rename to test/versioning/npm.spec.ts
index 5b18351809b6f6019671a51c433b7d44ef7b309d..5df9076edeed0928bf3d0c19c713b16d486e4a23 100644
--- a/test/versioning/npm.spec.js
+++ b/test/versioning/npm.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/npm');
+import { api as semver } from '../../lib/versioning/npm';
 
 describe('semver.isValid(input)', () => {
   it('should return null for irregular versions', () => {
diff --git a/test/versioning/pep440.spec.js b/test/versioning/pep440.spec.ts
similarity index 98%
rename from test/versioning/pep440.spec.js
rename to test/versioning/pep440.spec.ts
index 261d3d28f73d1e5ff328464ddba4099b6838d6ea..b35ab1758424484bc87ed5a74891eb46336a4941 100644
--- a/test/versioning/pep440.spec.js
+++ b/test/versioning/pep440.spec.ts
@@ -1,4 +1,4 @@
-const pep440 = require('../../lib/versioning/pep440');
+import pep440 from '../../lib/versioning/pep440';
 
 describe('pep440.isValid(input)', () => {
   it('should return null for irregular versions', () => {
diff --git a/test/versioning/poetry.spec.js b/test/versioning/poetry.spec.ts
similarity index 99%
rename from test/versioning/poetry.spec.js
rename to test/versioning/poetry.spec.ts
index be99521c5e62a78dd08f20f43e717c9dae845b5a..b0e792c79ae816a343cc9c4459424f8b09456d2e 100644
--- a/test/versioning/poetry.spec.js
+++ b/test/versioning/poetry.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/poetry');
+import { api as semver } from '../../lib/versioning/poetry';
 
 describe('semver.isValid(input)', () => {
   it('should return null for irregular versions', () => {
diff --git a/test/versioning/ruby.spec.js b/test/versioning/ruby.spec.ts
similarity index 97%
rename from test/versioning/ruby.spec.js
rename to test/versioning/ruby.spec.ts
index 65384b64ccbfc35b589009eed95a09f02341a19a..5d8d47cd6a690deced94e1b7e5d1a65bb5c0fc8e 100644
--- a/test/versioning/ruby.spec.js
+++ b/test/versioning/ruby.spec.ts
@@ -1,4 +1,4 @@
-const semverRuby = require('../../lib/versioning/ruby');
+import { api as semverRuby } from '../../lib/versioning/ruby';
 
 describe('semverRuby', () => {
   describe('.equals', () => {
@@ -61,7 +61,7 @@ describe('semverRuby', () => {
     });
 
     it('returns false when version is invalid', () => {
-      expect(semverRuby.isVersion()).toBe(false);
+      expect(semverRuby.isVersion(undefined)).toBe(false);
       expect(semverRuby.isVersion('')).toBe(false);
       expect(semverRuby.isVersion(null)).toBe(false);
       expect(semverRuby.isVersion('tottally-not-a-version')).toBe(false);
@@ -137,7 +137,7 @@ describe('semverRuby', () => {
     });
 
     it('returns false when version is invalid', () => {
-      expect(semverRuby.isStable()).toBe(false);
+      expect(semverRuby.isStable(undefined)).toBe(false);
       expect(semverRuby.isStable('')).toBe(false);
       expect(semverRuby.isStable(null)).toBe(false);
       expect(semverRuby.isStable('tottally-not-a-version')).toBe(false);
@@ -294,7 +294,7 @@ describe('semverRuby', () => {
     });
 
     it('returns false when version is invalid', () => {
-      expect(semverRuby.isVersion()).toBe(false);
+      expect(semverRuby.isVersion(undefined)).toBe(false);
       expect(semverRuby.isVersion('')).toBe(false);
       expect(semverRuby.isVersion(null)).toBe(false);
       expect(semverRuby.isVersion('tottally-not-a-version')).toBe(false);
@@ -338,7 +338,7 @@ describe('semverRuby', () => {
     });
 
     it('returns false when version is invalid', () => {
-      expect(semverRuby.isSingleVersion()).toBe(false);
+      expect(semverRuby.isSingleVersion(undefined)).toBe(false);
       expect(semverRuby.isSingleVersion('')).toBe(false);
       expect(semverRuby.isSingleVersion(null)).toBe(false);
       expect(semverRuby.isSingleVersion('tottally-not-a-version')).toBe(false);
@@ -358,6 +358,7 @@ describe('semverRuby', () => {
         ['1.2.3', '~> 1.0.3', 'pin', '1.0.4', '1.2.3'],
         ['4.7.8', '~> 4.7, >= 4.7.4', 'pin', '4.7.5', '4.7.8'],
       ].forEach(([expected, ...params]) => {
+        // @ts-ignore
         expect(semverRuby.getNewValue(...params)).toEqual(expected);
       });
     });
@@ -379,6 +380,7 @@ describe('semverRuby', () => {
         ['~> 1.0.0', '~> 1.0.3', 'bump', '1.0.3', '1.0.4'],
         ['~> 4.7.0, >= 4.7.9', '~> 4.7, >= 4.7.4', 'bump', '4.7.5', '4.7.9'],
       ].forEach(([expected, ...params]) => {
+        // @ts-ignore
         expect(semverRuby.getNewValue(...params)).toEqual(expected);
       });
     });
@@ -414,6 +416,7 @@ describe('semverRuby', () => {
           '2.20.0',
         ],
       ].forEach(([expected, ...params]) => {
+        // @ts-ignore
         expect(semverRuby.getNewValue(...params)).toEqual(expected);
       });
     });
diff --git a/test/versioning/semver.spec.js b/test/versioning/semver.spec.ts
similarity index 96%
rename from test/versioning/semver.spec.js
rename to test/versioning/semver.spec.ts
index 30d80432bfeeec6e871fdfa6e1971aa88bd5ae34..c6493f8fec55ca15a966f793f1b9fc0f2138bb92 100644
--- a/test/versioning/semver.spec.js
+++ b/test/versioning/semver.spec.ts
@@ -1,4 +1,4 @@
-const semver = require('../../lib/versioning/semver');
+import semver from '../../lib/versioning/semver';
 
 describe('semver.isValid(input)', () => {
   it('should return null for irregular versions', () => {
diff --git a/test/versioning/swift.spec.js b/test/versioning/swift.spec.ts
similarity index 97%
rename from test/versioning/swift.spec.js
rename to test/versioning/swift.spec.ts
index ad86d2009041b872bc26e43f28ac8de3180d4f27..e9c33ed0ccc7c4850753c51df6fae63bc7122b40 100644
--- a/test/versioning/swift.spec.js
+++ b/test/versioning/swift.spec.ts
@@ -1,3 +1,5 @@
+import swift from '../../lib/versioning/swift';
+
 const {
   getNewValue,
   isValid,
@@ -5,7 +7,7 @@ const {
   maxSatisfyingVersion,
   isLessThanRange,
   matches,
-} = require('../../lib/versioning/swift');
+} = swift;
 
 describe('isValid(input)', () => {
   it('understands Swift version ranges', () => {
@@ -78,6 +80,7 @@ describe('getNewValue()', () => {
       ['..."1.2.4"', 'auto', '1.2.3', '1.2.5', '..."1.2.5"'],
       ['..<"1.2.4"', 'auto', '1.2.3', '1.2.5', '..<"1.2.5"'],
     ].forEach(([range, strategy, fromVersion, toVersion, result]) => {
+      // @ts-ignore
       const newValue = getNewValue(range, strategy, fromVersion, toVersion);
       expect(newValue).toEqual(result);
     });
diff --git a/test/versioning/versioning-readmes.spec.js b/test/versioning/versioning-readmes.spec.ts
similarity index 75%
rename from test/versioning/versioning-readmes.spec.js
rename to test/versioning/versioning-readmes.spec.ts
index 6cc98995da753d2280f91ad93ecbc1505f87f866..4d7afafe337f1e6233562d7326f8377af8a9d5f2 100644
--- a/test/versioning/versioning-readmes.spec.js
+++ b/test/versioning/versioning-readmes.spec.ts
@@ -1,15 +1,15 @@
-const fs = require('fs-extra');
+import { readdir, readFile } from 'fs-extra';
 
 describe('versioning readmes', () => {
   it('has same questions for all version schemes', async () => {
-    const managers = (await fs.readdir('lib/versioning')).filter(
+    const managers = (await readdir('lib/versioning')).filter(
       item => !item.includes('.')
     );
-    let expectedHeaders;
+    let expectedHeaders: string[];
     for (const manager of managers) {
-      let readme;
+      let readme: string;
       try {
-        readme = await fs.readFile(
+        readme = await readFile(
           'lib/versioning/' + manager + '/readme.md',
           'utf8'
         );