function install(config) {
				if (
					arguments.length > 1 ||
					config instanceof Date ||
					Array.isArray(config) ||
					typeof config === "number"
				) {
					throw new TypeError(
						`FakeTimers.install called with ${String(
							config
						)} install requires an object parameter`
					);
				}

				if (_global.Date.isFake === true) {
					// Timers are already faked; this is a problem.
					// Make the user reset timers before continuing.
					throw new TypeError(
						"Can't install fake timers twice on the same global object."
					);
				}

				// eslint-disable-next-line no-param-reassign
				config = typeof config !== "undefined" ? config : {};
				config.shouldAdvanceTime = config.shouldAdvanceTime || false;
				config.advanceTimeDelta = config.advanceTimeDelta || 20;
				config.shouldClearNativeTimers =
					config.shouldClearNativeTimers || false;

				if (config.target) {
					throw new TypeError(
						"config.target is no longer supported. Use `withGlobal(target)` instead."
					);
				}

				let i, l;
				const clock = createClock(config.now, config.loopLimit);
				clock.shouldClearNativeTimers = config.shouldClearNativeTimers;

				clock.uninstall = function () {
					return uninstall(clock, config);
				};

				clock.methods = config.toFake || [];

				if (clock.methods.length === 0) {
					// do not fake nextTick by default - GitHub#126
					clock.methods = Object.keys(timers).filter(function (key) {
						return key !== "nextTick" && key !== "queueMicrotask";
					});
				}

				if (config.shouldAdvanceTime === true) {
					const intervalTick = doIntervalTick.bind(
						null,
						clock,
						config.advanceTimeDelta
					);
					const intervalId = _global.setInterval(
						intervalTick,
						config.advanceTimeDelta
					);
					clock.attachedInterval = intervalId;
				}

				if (clock.methods.includes("performance")) {
					const proto = (() => {
						if (hasPerformancePrototype) {
							return _global.Performance.prototype;
						}
						if (hasPerformanceConstructorPrototype) {
							return _global.performance.constructor.prototype;
						}
					})();
					if (proto) {
						Object.getOwnPropertyNames(proto).forEach(function (name) {
							if (name !== "now") {
								clock.performance[name] =
									name.indexOf("getEntries") === 0
										? NOOP_ARRAY
										: NOOP;
							}
						});
					} else if ((config.toFake || []).includes("performance")) {
						// user explicitly tried to fake performance when not present
						throw new ReferenceError(
							"non-existent performance object cannot be faked"
						);
					}
				}

				for (i = 0, l = clock.methods.length; i < l; i++) {
					const nameOfMethodToReplace = clock.methods[i];
					if (nameOfMethodToReplace === "hrtime") {
						if (
							_global.process &&
							typeof _global.process.hrtime === "function"
						) {
							hijackMethod(_global.process, nameOfMethodToReplace, clock);
						}
					} else if (nameOfMethodToReplace === "nextTick") {
						if (
							_global.process &&
							typeof _global.process.nextTick === "function"
						) {
							hijackMethod(_global.process, nameOfMethodToReplace, clock);
						}
					} else {
						hijackMethod(_global, nameOfMethodToReplace, clock);
					}
				}

				return clock;
			}
@param {Config=} [config] Optional config
@returns {Clock}