Skip to main content

no-floating-geolocation-watches

Require geolocation watch IDs to be retained so they can be cleared.

Rule catalog ID: R014

Targeted pattern scopeโ€‹

This rule targets browser geolocation watcher registration:

  • navigator.geolocation.watchPosition(...)
  • window.navigator.geolocation.watchPosition(...)
  • globalThis.navigator.geolocation.watchPosition(...)

The rule reports calls whose returned watch ID is immediately discarded. The watch ID is the handle needed to unregister the watcher with navigator.geolocation.clearWatch(...).

What this rule reportsโ€‹

The rule reports:

  • standalone watcher registration such as navigator.geolocation.watchPosition(onPosition);
  • voided watcher registration such as void navigator.geolocation.watchPosition(onPosition);
  • TypeScript-wrapped expressions that still discard the returned watch ID

It intentionally does not require same-function clearWatch() calls. Ownership can be transferred to a component instance, route lifecycle, returned value, or watch manager.

Why this rule existsโ€‹

watchPosition() installs repeated location monitoring callbacks. The browser returns a numeric ID for that watch, and clearWatch(id) uses that ID to remove the registered monitoring handlers. If the ID is discarded, the code that owns the lifecycle cannot reliably unregister the watcher.

Incorrectโ€‹

navigator.geolocation.watchPosition(onPosition);
void navigator.geolocation.watchPosition(onPosition, onError);

Correctโ€‹

const watchId = navigator.geolocation.watchPosition(onPosition);

navigator.geolocation.clearWatch(watchId);
return navigator.geolocation.watchPosition(onPosition);
registerWatch(navigator.geolocation.watchPosition(onPosition));

Behavior and migration notesโ€‹

Store the returned watch ID in the owner that will call clearWatch(). In UI code, that is usually the component, route, or view lifecycle. In shared libraries, returning the ID or passing it to a watcher manager keeps ownership explicit.

This rule does not autofix. Choosing the owner and cleanup point is a semantic decision.

ESLint flat config exampleโ€‹

import runtimeCleanup from "eslint-plugin-runtime-cleanup";

export default [
runtimeCleanup.configs.recommended,
];

When not to use itโ€‹

Do not enable this rule for code that intentionally creates page-lifetime geolocation watches and does not need explicit teardown. Prefer a narrow disable comment with a reason in those files.

Further readingโ€‹