TypeScript
@foresightjs/angular exports its binding types and common core types such as ForesightElementState, ForesightCallback, and ForesightRegisterOptionsWithoutElement:
import type { ForesightOptions, ForesightRegistration } from "@foresightjs/angular"
Other core types come from js.foresight directly:
import type { ElementBounds, ForesightRegisterResult, ForesightManagerData } from "js.foresight"
Angular prediction state is exposed as signals:
import type { ForesightStateSignal } from "@foresightjs/angular"
type Props = {
state: ForesightStateSignal
}
Typed metadata
Augment ForesightRegister, the global type registry, to define your metadata shape once in a .d.ts file included by your app's tsconfig.json:
import "js.foresight"
declare module "js.foresight" {
interface ForesightRegister {
meta: {
href: string
}
}
}
Declare meta as a required key in the registry. Writing meta?: AppMeta silently falls back to Record<string, unknown>. Put optionality on the fields inside it instead, for example meta: { href?: string }.
Registration options, callback state, events, devtools, and all framework bindings use this shape automatically. No generics are needed.
import { ForesightManager } from "js.foresight"
ForesightManager.instance.register({
element: document.querySelector("a")!,
meta: { href: "/about" },
callback: state => {
console.log(state.meta.href.toUpperCase())
},
})
Without augmentation, ForesightMeta defaults to Record<string, unknown>. Metadata remains optional and defaults to {}. Unregistered framework snapshots also contain {}, so use optional fields such as href?: string if you read them before registration or register elements without metadata. Augmentation only changes types, it does not validate metadata at runtime.
Most Used Internal types
ForesightElementState
This is the main type used in ForesightJS: the flat, immutable state snapshot of a registered element. Your callback receives it, most events carry it as state, and register() returns it (plus a few functions, see ForesightRegisterResult). The reference is replaced on every logical change, never mutated. Geometry-only changes use ElementBounds, on their own subscription channel. Scrolling can still change logical state, such as viewport visibility or prediction status.
type ForesightElementState = {
id: string // unique id assigned during registration
name: string // name visible in the devtools
meta: ForesightMeta
hitSlop: Exclude<HitSlop, number> // normalized hit slop applied to this element
isLimitedConnection: boolean
isIntersectingWithViewport: boolean
isRegistered: boolean
isActive: boolean
isParked: boolean // detached from the DOM, kept registered but inactive until it reconnects
isEnabled: boolean
isPredicted: boolean
isCallbackRunning: boolean
hitCount: number
registerCount: number // amount of times this element has been (re)registered
durationMs: number | undefined // duration of the most recent callback run
status: "error" | "success" | undefined // status of the most recent callback
error: string | null
reactivateAfter: number
}
See the registration return value for what each field means.
ElementBounds
The element's geometry: its measured rect and the hitSlop-expanded rect used for interaction detection. Visible elements' position and size changes are published on a separate channel (getBounds/subscribeToBounds) and kept out of ForesightElementState, so geometry-only updates do not notify state subscribers.
type ElementBounds = {
originalRect: DOMRectReadOnly // as returned by getBoundingClientRect()
expandedRect: Readonly<Rect> // originalRect + hitSlop
}
ForesightRegisterResult
What ForesightManager.instance.register() returns: the element's state at registration time plus control functions.
type ForesightRegisterResult = ForesightElementState & {
unregister: () => void
subscribe: (listener: () => void) => () => void // logical state changes; returns an unsubscribe function
getSnapshot: () => ForesightElementState // current state snapshot, stable reference across scrolls
subscribeToBounds: (listener: () => void) => () => void // geometry changes (every scroll/resize tick)
getBounds: () => ElementBounds // current geometry snapshot
}
CallbackHitType
type CallbackHitType =
| { kind: "mouse"; subType: "hover" | "trajectory" }
| { kind: "tab"; subType: "forwards" | "reverse" }
| { kind: "scroll"; subType: "up" | "down" | "left" | "right" }
| { kind: "touch"; subType?: string }
| { kind: "viewport"; subType?: string }
CurrentDeviceStrategy
Represents the current input method being used. ForesightJS automatically detects and switches between strategies.
type CurrentDeviceStrategy = "mouse" | "touch" | "pen"
ForesightManagerData
Snapshot of the current ForesightManager state, including all global settings, registered elements, and interaction statistics. This is primarily used for debugging, monitoring, and development purposes.
This data is returned in the managerSettingsChanged event or by calling ForesightManager.instance.getManagerData manually.
type ForesightManagerData = {
registeredElements: ReadonlyMap<ForesightElement, ForesightElementState> // See above for ForesightElementState
globalSettings: Readonly<ForesightManagerSettings> // See configuration for global settings
globalCallbackHits: Readonly<CallbackHits> // See above for CallbackHitType, this is that but all of them combined
eventListeners: ReadonlyMap<keyof ForesightEventMap, ReadonlySet<ForesightEventListener>> // All event listeners currently listening
currentDeviceStrategy: CurrentDeviceStrategy
activeElementCount: number
parkedElementCount: number // elements detached from the DOM, waiting to reconnect
loadedModules: ForesightModules // which handlers/predictors are lazily loaded
}
Helper Types
ForesightCallback
The callback function type used when registering elements. Receives the ForesightElementState of the element that triggered the callback.
type ForesightCallback = (state: ForesightElementState) => void
This is useful when registering multiple elements with a shared callback, as you can identify which element triggered it:
const myCallback: ForesightCallback = state => {
console.log(`Triggered by: ${state.name}`)
}
ForesightRegisterOptionsWithoutElement
Useful for if you want to create a custom button component in a modern framework. And you want to have the ForesightRegisterOptions used in ForesightManager.instance.register({}) without the element as the element will be the ref of the component.
This type is the options object you pass to the useForesight hook in React, the useForesight composable in Vue, and Angular's [fsForesight] / ForesightService APIs.
type ForesightButtonProps = {
registerOptions: ForesightRegisterOptionsWithoutElement
}