chore(lint): no-explicit-any in app (batch 3)

Covers use-web-scrollbar, stream-strategy, dictation-stream-sender test,
terminal-perf helper, checkout-git-actions-store test, and
web-desktop-scrollbar.
This commit is contained in:
Mohamed Boudra
2026-04-24 06:51:40 +07:00
parent de27e31116
commit 13d3de2b1d
6 changed files with 64 additions and 27 deletions

View File

@@ -100,7 +100,19 @@ function buildWorkspaceUrl(workspaceId: string): string {
export async function getTerminalBufferText(page: Page): Promise<string> {
return page.evaluate(() => {
const term = (window as any).__paseoTerminal;
const term = (
window as Window & {
__paseoTerminal?: {
buffer: {
active: {
length: number;
getLine: (i: number) => { translateToString: (trim: boolean) => string } | null;
};
};
onWriteParsed: (cb: () => void) => { dispose: () => void };
};
}
).__paseoTerminal;
if (!term) {
return "";
}
@@ -205,12 +217,16 @@ export interface LatencySample {
*/
export async function measureKeystrokeLatency(page: Page, char: string): Promise<number> {
await page.evaluate(() => {
const term = (window as any).__paseoTerminal;
if (!term) {
const win = window as Window & {
__paseoTerminal?: { onWriteParsed: (cb: () => void) => { dispose: () => void } };
__perfKeystroke?: { promise: Promise<number> | null };
};
if (!win.__paseoTerminal) {
throw new Error("__paseoTerminal not available");
}
const term = win.__paseoTerminal;
const state = ((window as any).__perfKeystroke = {
const state = (win.__perfKeystroke = {
promise: null as Promise<number> | null,
});
@@ -236,7 +252,11 @@ export async function measureKeystrokeLatency(page: Page, char: string): Promise
await page.keyboard.press(char);
return page.evaluate(() => (window as any).__perfKeystroke.promise);
return page.evaluate(
() =>
(window as unknown as { __perfKeystroke: { promise: Promise<number> } }).__perfKeystroke
.promise,
);
}
export function computePercentile(samples: number[], p: number): number {

View File

@@ -32,9 +32,9 @@ export type StreamNearBottomInput = StreamViewportMetrics & {
};
export interface StreamEdgeSlotProps {
ListHeaderComponent?: ReactElement | ComponentType<any> | null;
ListHeaderComponent?: ReactElement | ComponentType<unknown> | null;
ListHeaderComponentStyle?: StyleProp<ViewStyle>;
ListFooterComponent?: ReactElement | ComponentType<any> | null;
ListFooterComponent?: ReactElement | ComponentType<unknown> | null;
ListFooterComponentStyle?: StyleProp<ViewStyle>;
}
@@ -85,7 +85,7 @@ export interface StreamStrategy {
isNearBottom: (input: StreamNearBottomInput) => boolean;
getBottomOffset: (metrics: StreamViewportMetrics) => number;
getEdgeSlotProps: (
component: ReactElement | ComponentType<any> | null,
component: ReactElement | ComponentType<unknown> | null,
gapSize: number,
) => StreamEdgeSlotProps;
getMaintainVisibleContentPosition: () => MaintainVisibleContentPositionConfig | undefined;
@@ -262,7 +262,7 @@ export function getBottomOffsetForStreamRenderStrategy(
export function getStreamEdgeSlotProps(params: {
strategy: StreamStrategy;
component: ReactElement | ComponentType<any> | null;
component: ReactElement | ComponentType<unknown> | null;
gapSize: number;
}): StreamEdgeSlotProps {
return params.strategy.getEdgeSlotProps(params.component, params.gapSize);

View File

@@ -60,8 +60,12 @@ export function useWebElementScrollbar(
if (!element) return;
element.setAttribute("data-hide-scrollbar", "");
(element.style as any).scrollbarWidth = "none";
(element.style as any).msOverflowStyle = "none";
(
element.style as CSSStyleDeclaration & { scrollbarWidth: string; msOverflowStyle: string }
).scrollbarWidth = "none";
(
element.style as CSSStyleDeclaration & { scrollbarWidth: string; msOverflowStyle: string }
).msOverflowStyle = "none";
ensureHideScrollbarStyle();
function update() {
@@ -90,8 +94,12 @@ export function useWebElementScrollbar(
element.removeEventListener("scroll", update);
resizeObserver.disconnect();
element.removeAttribute("data-hide-scrollbar");
(element.style as any).scrollbarWidth = "";
(element.style as any).msOverflowStyle = "";
(
element.style as CSSStyleDeclaration & { scrollbarWidth: string; msOverflowStyle: string }
).scrollbarWidth = "";
(
element.style as CSSStyleDeclaration & { scrollbarWidth: string; msOverflowStyle: string }
).msOverflowStyle = "";
};
}, [contentRef, elementRef, enabled]);

View File

@@ -27,7 +27,15 @@ const HANDLE_WIDTH_TRANSITION_DURATION_MS = 240;
const HANDLE_SCROLL_VISIBILITY_MS = 1200;
const HANDLE_SCROLL_ACTIVE_MS = 110;
function readClientY(event: any): number | null {
interface PointerLikeEvent {
clientY?: number;
pageY?: number;
nativeEvent?: { clientY?: number; pageY?: number; preventDefault?: () => void };
preventDefault?: () => void;
stopPropagation?: () => void;
}
function readClientY(event: PointerLikeEvent): number | null {
const value =
event?.nativeEvent?.clientY ?? event?.clientY ?? event?.nativeEvent?.pageY ?? event?.pageY;
return typeof value === "number" ? value : null;
@@ -281,7 +289,7 @@ export function WebDesktopScrollbarOverlay({
});
}, [applyDragDelta]);
const startWebDrag = useCallback((event: any) => {
const startWebDrag = useCallback((event: PointerLikeEvent) => {
if (!platformIsWeb) {
return;
}
@@ -371,7 +379,7 @@ export function WebDesktopScrollbarOverlay({
transitionProperty: "transform",
transitionDuration: `${handleTravelDurationMs}ms`,
transitionTimingFunction: "linear",
} as any),
} as object),
],
[thumbRegionHeight, thumbRegionOffset, handleCursor, handleTravelDurationMs],
);
@@ -391,7 +399,7 @@ export function WebDesktopScrollbarOverlay({
transitionProperty: "opacity, width, background-color",
transitionDuration: `${HANDLE_FADE_DURATION_MS}ms, ${HANDLE_WIDTH_TRANSITION_DURATION_MS}ms, ${HANDLE_FADE_DURATION_MS}ms`,
transitionTimingFunction: "ease-out, cubic-bezier(0.22, 0.75, 0.2, 1), ease-out",
} as any),
} as object),
],
[handleInsetTop, geometry.handleSize, handleWidth, handleColor, handleOpacity],
);
@@ -409,7 +417,7 @@ export function WebDesktopScrollbarOverlay({
onPointerLeave: handleGrabHoverOut,
onMouseEnter: handleGrabHoverIn,
onMouseLeave: handleGrabHoverOut,
} as any)
} as object)
: null)}
>
<View style={handleStyle} pointerEvents="none" />

View File

@@ -1,4 +1,5 @@
import { describe, expect, it } from "vitest";
import type { DaemonClient } from "@server/client/daemon-client";
import { DictationStreamSender } from "@/dictation/dictation-stream-sender";
@@ -55,7 +56,7 @@ describe("DictationStreamSender", () => {
const client = new FakeDaemonClient();
const ids = ["d1"];
const sender = new DictationStreamSender({
client: client as any,
client: client as unknown as DaemonClient,
format: "audio/pcm;rate=16000;bits=16",
createDictationId: () => ids.shift() ?? "dX",
});
@@ -76,7 +77,7 @@ describe("DictationStreamSender", () => {
const client = new FakeDaemonClient();
const ids = ["d1", "d2"];
const sender = new DictationStreamSender({
client: client as any,
client: client as unknown as DaemonClient,
format: "audio/pcm;rate=16000;bits=16",
createDictationId: () => ids.shift() ?? "dX",
});
@@ -99,7 +100,7 @@ describe("DictationStreamSender", () => {
const client = new FakeDaemonClient();
const ids = ["d1"];
const sender = new DictationStreamSender({
client: client as any,
client: client as unknown as DaemonClient,
format: "audio/pcm;rate=16000;bits=16",
createDictationId: () => ids.shift() ?? "dX",
});
@@ -120,7 +121,7 @@ describe("DictationStreamSender", () => {
client.isConnected = false;
const ids = ["d1"];
const sender = new DictationStreamSender({
client: client as any,
client: client as unknown as DaemonClient,
format: "audio/pcm;rate=16000;bits=16",
createDictationId: () => ids.shift() ?? "dX",
});

View File

@@ -52,18 +52,18 @@ describe("checkout-git-actions-store", () => {
vi.useFakeTimers();
__resetCheckoutGitActionsStoreForTests();
appQueryClient.clear();
useSessionStore.setState((state) => ({ ...state, sessions: {} as any }));
useSessionStore.setState((state) => ({ ...state, sessions: {} }));
});
afterEach(() => {
vi.useRealTimers();
__resetCheckoutGitActionsStoreForTests();
appQueryClient.clear();
useSessionStore.setState((state) => ({ ...state, sessions: {} as any }));
useSessionStore.setState((state) => ({ ...state, sessions: {} }));
});
it("shares pending state per checkout and de-dupes in-flight calls", async () => {
const deferred = createDeferred<any>();
const deferred = createDeferred<unknown>();
const client = {
checkoutCommit: vi.fn(() => deferred.promise),
};
@@ -71,8 +71,8 @@ describe("checkout-git-actions-store", () => {
useSessionStore.setState((state) => ({
...state,
sessions: {
...(state.sessions as any),
[serverId]: { client } as any,
...state.sessions,
[serverId]: { client } as unknown as (typeof state.sessions)[string],
},
}));