From c85e66f563b2202ac9f4d0efc114d963f685a501 Mon Sep 17 00:00:00 2001 From: Daniel Riera Date: Wed, 7 Jan 2026 09:59:33 -0500 Subject: [PATCH] [PM-29516] Remove ts strict ignore in utils index (#18047) * use type safe generics for throttle and debounce, account for the change were event isn't passed * read gloabl once * check for styles before setting * narrow keywords index * narrow bitwardenAutofillInit for callback * nullish coalescing operator on value for prop attributes --- .../autofill-overlay-content.service.ts | 14 ++--- apps/browser/src/autofill/utils/index.ts | 51 +++++++++++-------- 2 files changed, 39 insertions(+), 26 deletions(-) diff --git a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts index 817a7cca43c..2087b0640fb 100644 --- a/apps/browser/src/autofill/services/autofill-overlay-content.service.ts +++ b/apps/browser/src/autofill/services/autofill-overlay-content.service.ts @@ -1659,17 +1659,19 @@ export class AutofillOverlayContentService implements AutofillOverlayContentServ return false; }; const scrollHandler = this.useEventHandlersMemo( - throttle(async (event) => { + throttle(async (event: Event) => { + const scrollY = globalThis.scrollY; + const scrollX = globalThis.scrollX; if ( - currentScrollY !== globalThis.scrollY || - currentScrollX !== globalThis.scrollX || - eventTargetContainsFocusedField(event.target) + currentScrollY !== scrollY || + currentScrollX !== scrollX || + (event.target instanceof Element && eventTargetContainsFocusedField(event.target)) ) { repositionHandler(event); } - currentScrollY = globalThis.scrollY; - currentScrollX = globalThis.scrollX; + currentScrollY = scrollY; + currentScrollX = scrollX; }, 50), AUTOFILL_OVERLAY_HANDLE_SCROLL, ); diff --git a/apps/browser/src/autofill/utils/index.ts b/apps/browser/src/autofill/utils/index.ts index a3d61c7f0b2..dc07ca1e258 100644 --- a/apps/browser/src/autofill/utils/index.ts +++ b/apps/browser/src/autofill/utils/index.ts @@ -1,5 +1,3 @@ -// FIXME: Update this file to be type safe and remove this and next line -// @ts-strict-ignore import { FieldRect } from "../background/abstractions/overlay.background"; import { AutofillPort } from "../enums/autofill-port.enum"; import { FillableFormFieldElement, FormElementWithAttribute, FormFieldElement } from "../types"; @@ -144,11 +142,14 @@ export function setElementStyles( } for (const styleProperty in styles) { - element.style.setProperty( - styleProperty.replace(/([a-z])([A-Z])/g, "$1-$2"), // Convert camelCase to kebab-case - styles[styleProperty], - priority ? "important" : undefined, - ); + const styleValue = styles[styleProperty]; + if (styleValue !== undefined) { + element.style.setProperty( + styleProperty.replace(/([a-z])([A-Z])/g, "$1-$2"), // Convert camelCase to kebab-case + styleValue, + priority ? "important" : undefined, + ); + } } } @@ -175,12 +176,13 @@ export function setupExtensionDisconnectAction(callback: (port: chrome.runtime.P * @param windowContext - The global window context */ export function setupAutofillInitDisconnectAction(windowContext: Window) { - if (!windowContext.bitwardenAutofillInit) { + const bitwardenAutofillInit = windowContext.bitwardenAutofillInit; + if (!bitwardenAutofillInit) { return; } const onDisconnectCallback = () => { - windowContext.bitwardenAutofillInit.destroy(); + bitwardenAutofillInit.destroy(); delete windowContext.bitwardenAutofillInit; }; setupExtensionDisconnectAction(onDisconnectCallback); @@ -357,7 +359,7 @@ export function getAttributeBoolean( */ export function getPropertyOrAttribute(element: HTMLElement, attributeName: string): string | null { if (attributeName in element) { - return (element as FormElementWithAttribute)[attributeName]; + return (element as FormElementWithAttribute)[attributeName] ?? null; } return element.getAttribute(attributeName); @@ -369,9 +371,12 @@ export function getPropertyOrAttribute(element: HTMLElement, attributeName: stri * @param callback - The callback function to throttle. * @param limit - The time in milliseconds to throttle the callback. */ -export function throttle(callback: (_args: any) => any, limit: number) { +export function throttle unknown>( + callback: FunctionType, + limit: number, +): (this: ThisParameterType, ...args: Parameters) => void { let waitingDelay = false; - return function (...args: unknown[]) { + return function (this: ThisParameterType, ...args: Parameters) { if (!waitingDelay) { callback.apply(this, args); waitingDelay = true; @@ -387,9 +392,14 @@ export function throttle(callback: (_args: any) => any, limit: number) { * @param delay - The time in milliseconds to debounce the callback. * @param immediate - Determines whether the callback should run immediately. */ -export function debounce(callback: (_args: any) => any, delay: number, immediate?: boolean) { - let timeout: NodeJS.Timeout; - return function (...args: unknown[]) { +export function debounce unknown>( + callback: FunctionType, + delay: number, + immediate?: boolean, +): (this: ThisParameterType, ...args: Parameters) => void { + let timeout: ReturnType | null = null; + + return function (this: ThisParameterType, ...args: Parameters) { const callImmediately = !!immediate && !timeout; if (timeout) { @@ -430,16 +440,17 @@ export function getSubmitButtonKeywordsSet(element: HTMLElement): Set { const keywordsSet = new Set(); for (let i = 0; i < keywords.length; i++) { - if (typeof keywords[i] === "string") { + const keyword = keywords[i]; + if (typeof keyword === "string") { // Iterate over all keywords metadata and split them by non-letter characters. // This ensures we check against individual words and not the entire string. - keywords[i] + keyword .toLowerCase() .replace(/[-\s]/g, "") .split(/[^\p{L}]+/gu) - .forEach((keyword) => { - if (keyword) { - keywordsSet.add(keyword); + .forEach((splitKeyword) => { + if (splitKeyword) { + keywordsSet.add(splitKeyword); } }); }