noLateCurrentTargetAccess (JavaScript)
Summary
Section titled “Summary”- Rule available since:
v2.6.8 - Diagnostic Category:
lint/nursery/noLateCurrentTargetAccess - This rule doesn’t have a fix.
- The default severity of this rule is warning.
- Sources:
- Inspired from
unicorn/no-late-current-target-access
- Inspired from
How to configure
Section titled “How to configure”{ "linter": { "rules": { "nursery": { "noLateCurrentTargetAccess": "error" } } }}Description
Section titled “Description”Disallow reading event.currentTarget after the browser has finished handling the event.
event.currentTarget is the element that the event handler was added to. The browser
only sets it while it runs the event handlers for the event, one after another. When a
handler pauses, the browser moves on without waiting for it and resets currentTarget
to null. Reading currentTarget afterwards gives null instead of the element.
Code in a handler reads currentTarget too late in these cases:
- The code comes after an
await, ayield, or afor awaitloop in the handler. - The code is in a function nested inside the handler, such as a
setTimeout()or.then()callback. The nested function can run after the handler has finished.
Save event.currentTarget to a variable before the handler pauses, and use that variable instead.
The rule checks a function parameter whose name looks like an event, such as e,
event, evt, or a camelCase name ending with Event like clickEvent. In TypeScript,
it also checks parameters with an event type, such as MouseEvent or React’s
SyntheticEvent, and ignores parameters with a type that isn’t an event, such as string.
The rule has these limitations:
- Every
currentTargetread inside a nested function is reported, even when the nested function runs right away, like the callback ofarray.map(). SavecurrentTargetto a variable in the handler to make it clear that it’s read in time. - The rule doesn’t follow the order in which code runs. A read is reported when an
awaitappears earlier in the handler, even if theawaitis in a branch that never runs together with the read. - When the event is passed to another function, reads inside that function are not checked.
Examples
Section titled “Examples”Invalid
Section titled “Invalid”element.addEventListener("click", async (event) => { await save(); event.currentTarget.disabled = false;});code-block.js:3:5 lint/nursery/noLateCurrentTargetAccess ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ event.currentTarget is read after the event handler pauses.
1 │ element.addEventListener("click", async (event) => {
2 │ await save();
> 3 │ event.currentTarget.disabled = false;
│ ^^^^^^^^^^^^^^^^^^^
4 │ });
5 │
ℹ The event handler pauses here.
1 │ element.addEventListener("click", async (event) => {
> 2 │ await save();
│ ^^^^^^^^^^^^
3 │ event.currentTarget.disabled = false;
4 │ });
ℹ When the handler pauses, the browser finishes handling the event and sets currentTarget to null.
ℹ Save event.currentTarget to a variable before the event handler pauses, and use that variable instead.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
element.addEventListener("click", (event) => { setTimeout(() => { event.currentTarget.focus(); });});code-block.js:3:9 lint/nursery/noLateCurrentTargetAccess ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
⚠ event.currentTarget is read inside a function nested in the event handler.
1 │ element.addEventListener("click", (event) => {
2 │ setTimeout(() => {
> 3 │ event.currentTarget.focus();
│ ^^^^^^^^^^^^^^^^^^^
4 │ });
5 │ });
ℹ The nested function may run after the browser finishes handling the event, when currentTarget is null.
ℹ Save event.currentTarget to a variable in the event handler, and use that variable in the nested function.
ℹ This rule belongs to the nursery group, which means it is not yet stable and may change in the future. Visit https://biomejs.dev/linter/#nursery for more information.
element.addEventListener("click", async (event) => { const button = event.currentTarget; button.disabled = true; await save(); button.disabled = false;});
element.addEventListener("click", (event) => { const { currentTarget } = event; setTimeout(() => { currentTarget.focus(); });});Related links
Section titled “Related links”Copyright (c) 2023-present Biome Developers and Contributors.