const location = new URL('', 'http://example.com'); let listeners: (() => void)[] = []; let entries = [{ state: null, href: location.href }]; let index = 0; let currentState: any = null; const history = { get state() { return currentState; }, pushState(state: any, _: string, path: string) { Object.assign(location, new URL(path, location.origin)); currentState = state; entries = entries.slice(0, index + 1); entries.push({ state, href: location.href }); index = entries.length - 1; }, replaceState(state: any, _: string, path: string) { Object.assign(location, new URL(path, location.origin)); currentState = state; entries[index] = { state, href: location.href }; }, go(n: number) { setTimeout(() => { if ( (n > 0 && n < entries.length - index) || (n < 0 && Math.abs(n) <= index) ) { index += n; const entry = entries[index]; Object.assign(location, new URL(entry.href)); currentState = entry.state; listeners.forEach((cb) => cb()); } }, 0); }, back() { this.go(-1); }, forward() { this.go(1); }, }; const addEventListener = (type: 'popstate', listener: () => void) => { if (type === 'popstate') { listeners.push(listener); } }; const removeEventListener = (type: 'popstate', listener: () => void) => { if (type === 'popstate') { listeners = listeners.filter((cb) => cb !== listener); } }; const window = { document: { title: '' }, location, history, addEventListener, removeEventListener, get window() { return window; }, }; export default window;