chore(lint): retire 19 explicit anys, ratchet to 49 warnings (#210)

Event handlers typed as React.MouseEvent, join errors as Error, the
service-worker session setter as strings, the UIA policy map and the
webkitAudioContext probe as narrow shapes. No behaviour change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
This commit is contained in:
2026-09-20 14:13:55 -04:00
co-authored by Claude Opus 5
parent af1c0ee184
commit af244bba75
14 changed files with 24 additions and 19 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
"build": "vite build", "build": "vite build",
"preview": "vite preview", "preview": "vite preview",
"lint": "npm run check:eslint && npm run check:prettier", "lint": "npm run check:eslint && npm run check:prettier",
"check:eslint": "eslint src/* --max-warnings 68", "check:eslint": "eslint src/* --max-warnings 49",
"check:prettier": "prettier --check .", "check:prettier": "prettier --check .",
"fix:prettier": "prettier --write .", "fix:prettier": "prettier --write .",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
+1 -1
View File
@@ -30,7 +30,7 @@ export const ImageOverlay = as<'div', ImageOverlayProps>(
<Modal <Modal
className={ModalWide} className={ModalWide}
size="500" size="500"
onContextMenu={(evt: any) => evt.stopPropagation()} onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
> >
{renderViewer({ {renderViewer({
src, src,
@@ -114,7 +114,7 @@ export function ReadTextFile({ body, mimeType, url, encInfo, renderViewer }: Rea
<Modal <Modal
className={ModalWide} className={ModalWide}
size="500" size="500"
onContextMenu={(evt: any) => evt.stopPropagation()} onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
> >
{renderViewer({ {renderViewer({
name: body, name: body,
@@ -203,7 +203,7 @@ export function ReadPdfFile({ body, mimeType, url, encInfo, renderViewer }: Read
<Modal <Modal
className={ModalWide} className={ModalWide}
size="500" size="500"
onContextMenu={(evt: any) => evt.stopPropagation()} onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
> >
{renderViewer({ {renderViewer({
name: body, name: body,
@@ -143,7 +143,7 @@ export const ImageContent = as<'div', ImageContentProps>(
<Modal <Modal
className={ModalWide} className={ModalWide}
size="500" size="500"
onContextMenu={(evt: any) => evt.stopPropagation()} onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
> >
{renderViewer({ {renderViewer({
src: srcState.data, src: srcState.data,
+1 -1
View File
@@ -88,7 +88,7 @@ export function UserHero({ userId, avatarUrl, presence }: UserHeroProps) {
<Modal <Modal
size="500" size="500"
className={ModalMobileFull} className={ModalMobileFull}
onContextMenu={(evt: any) => evt.stopPropagation()} onContextMenu={(evt: React.MouseEvent) => evt.stopPropagation()}
> >
<ImageViewer <ImageViewer
src={viewAvatar} src={viewAvatar}
+1 -1
View File
@@ -41,7 +41,7 @@ export function CallMemberCard({ member }: CallMemberCardProps) {
className={css.CallMemberCard} className={css.CallMemberCard}
variant="SurfaceVariant" variant="SurfaceVariant"
radii="500" radii="500"
onClick={(evt: any) => onClick={(evt: React.MouseEvent) =>
openUserProfile( openUserProfile(
room.roomId, room.roomId,
undefined, undefined,
+1 -1
View File
@@ -36,7 +36,7 @@ export function RoomTombstone({ roomId, body, replacementRoomId }: RoomTombstone
<Text size="T400">{body || 'This room has been replaced and is no longer active.'}</Text> <Text size="T400">{body || 'This room has been replaced and is no longer active.'}</Text>
{joinState.status === AsyncStatus.Error && ( {joinState.status === AsyncStatus.Error && (
<Text style={{ color: color.Critical.Main }} size="T200"> <Text style={{ color: color.Critical.Main }} size="T200">
{(joinState.error as any)?.message ?? 'Failed to join replacement room!'} {(joinState.error as Error | undefined)?.message ?? 'Failed to join replacement room!'}
</Text> </Text>
)} )}
</Box> </Box>
+5 -5
View File
@@ -214,7 +214,7 @@ export const MessageAllReactionItem = as<
return ( return (
<> <>
<Overlay <Overlay
onContextMenu={(evt: any) => { onContextMenu={(evt: React.MouseEvent) => {
evt.stopPropagation(); evt.stopPropagation();
}} }}
open={open} open={open}
@@ -1087,7 +1087,7 @@ export const Message = React.memo(
const handleContextMenu: MouseEventHandler<HTMLDivElement> = (evt) => { const handleContextMenu: MouseEventHandler<HTMLDivElement> = (evt) => {
if (evt.altKey || !window.getSelection()?.isCollapsed || edit) return; if (evt.altKey || !window.getSelection()?.isCollapsed || edit) return;
const tag = (evt.target as any).tagName; const tag = (evt.target as HTMLElement | null)?.tagName;
if (typeof tag === 'string' && tag.toLowerCase() === 'a') return; if (typeof tag === 'string' && tag.toLowerCase() === 'a') return;
evt.preventDefault(); evt.preventDefault();
if (coarsePointer) { if (coarsePointer) {
@@ -1155,7 +1155,7 @@ export const Message = React.memo(
after={<Icon size="100" src={Icons.ReplyArrow} />} after={<Icon size="100" src={Icons.ReplyArrow} />}
radii="300" radii="300"
data-event-id={mEvent.getId()} data-event-id={mEvent.getId()}
onClick={(evt: any) => { onClick={(evt: React.MouseEvent<HTMLButtonElement>) => {
onReplyClick(evt); onReplyClick(evt);
closeMenu(); closeMenu();
}} }}
@@ -1232,7 +1232,7 @@ export const Message = React.memo(
after={<Icon src={Icons.ThreadPlus} size="100" />} after={<Icon src={Icons.ThreadPlus} size="100" />}
radii="300" radii="300"
data-event-id={mEvent.getId()} data-event-id={mEvent.getId()}
onClick={(evt: any) => { onClick={(evt: React.MouseEvent<HTMLButtonElement>) => {
onReplyClick(evt, true); onReplyClick(evt, true);
closeMenu(); closeMenu();
}} }}
@@ -1599,7 +1599,7 @@ export const Event = React.memo(
const stateEvent = typeof mEvent.getStateKey() === 'string'; const stateEvent = typeof mEvent.getStateKey() === 'string';
const handleContextMenu: MouseEventHandler<HTMLDivElement> = (evt) => { const handleContextMenu: MouseEventHandler<HTMLDivElement> = (evt) => {
if (evt.altKey || !window.getSelection()?.isCollapsed) return; if (evt.altKey || !window.getSelection()?.isCollapsed) return;
const tag = (evt.target as any).tagName; const tag = (evt.target as HTMLElement | null)?.tagName;
if (typeof tag === 'string' && tag.toLowerCase() === 'a') return; if (typeof tag === 'string' && tag.toLowerCase() === 'a') return;
evt.preventDefault(); evt.preventDefault();
setMenuAnchor({ setMenuAnchor({
+1 -1
View File
@@ -202,7 +202,7 @@ export const Reactions = as<'div', ReactionsProps>(
)} )}
{reactions.length > 0 && ( {reactions.length > 0 && (
<Overlay <Overlay
onContextMenu={(evt: any) => { onContextMenu={(evt: React.MouseEvent) => {
evt.stopPropagation(); evt.stopPropagation();
}} }}
open={!!viewer} open={!!viewer}
+1 -1
View File
@@ -378,7 +378,7 @@ export function SpaceTombstone({ roomId, replacementRoomId }: SpaceTombstoneProp
<Text size="T200">This space has been replaced and is no longer active.</Text> <Text size="T200">This space has been replaced and is no longer active.</Text>
{joinState.status === AsyncStatus.Error && ( {joinState.status === AsyncStatus.Error && (
<Text className={BreakWord} style={{ color: color.Critical.Main }} size="T200"> <Text className={BreakWord} style={{ color: color.Critical.Main }} size="T200">
{(joinState.error as any)?.message ?? 'Failed to join replacement space!'} {(joinState.error as Error | undefined)?.message ?? 'Failed to join replacement space!'}
</Text> </Text>
)} )}
</Box> </Box>
+1 -1
View File
@@ -368,7 +368,7 @@ export class CallEmbed {
return this.listenEvent('preparing', callback); return this.listenEvent('preparing', callback);
} }
public onPreparingError(callback: (error: any) => void) { public onPreparingError(callback: (error: unknown) => void) {
return this.listenEvent('error:preparing', callback); return this.listenEvent('error:preparing', callback);
} }
+3 -1
View File
@@ -68,7 +68,9 @@ export const isMLDenoiseSupported = (): boolean => {
// 1. AudioContext/webkitAudioContext (Web Audio API) // 1. AudioContext/webkitAudioContext (Web Audio API)
// 2. AudioWorklet (Real-time processing in a background thread) // 2. AudioWorklet (Real-time processing in a background thread)
// 3. getUserMedia (Microphone access) // 3. getUserMedia (Microphone access)
const hasAudioContext = !!(window.AudioContext || (window as any).webkitAudioContext); const hasAudioContext = !!(
window.AudioContext || (window as Window & { webkitAudioContext?: unknown }).webkitAudioContext
);
// Use `typeof` rather than `!!AudioWorkletNode`: on a browser that has // Use `typeof` rather than `!!AudioWorkletNode`: on a browser that has
// AudioContext but no AudioWorkletNode binding (older Safari/Edge), a bare // AudioContext but no AudioWorkletNode binding (older Safari/Edge), a bare
// reference throws ReferenceError, making this feature-detection helper throw // reference throws ReferenceError, making this feature-detection helper throw
+4 -1
View File
@@ -72,7 +72,10 @@ export const getLoginTermUrl = (params: UIAParams): string | undefined => {
if (terms.policies === null) return undefined; if (terms.policies === null) return undefined;
if ('privacy_policy' in terms.policies && typeof terms.policies.privacy_policy === 'object') { if ('privacy_policy' in terms.policies && typeof terms.policies.privacy_policy === 'object') {
if (terms.policies.privacy_policy === null) return undefined; if (terms.policies.privacy_policy === null) return undefined;
const langToPolicy = terms.policies.privacy_policy as Record<string, any>; const langToPolicy = terms.policies.privacy_policy as Record<
string,
{ url?: string } | undefined
>;
const url = langToPolicy.en?.url; const url = langToPolicy.en?.url;
if (typeof url === 'string') return url; if (typeof url === 'string') return url;
+1 -1
View File
@@ -63,7 +63,7 @@ async function cleanupDeadClients() {
}); });
} }
function setSession(clientId: string, accessToken: any, baseUrl: any) { function setSession(clientId: string, accessToken: string, baseUrl: string) {
if (typeof accessToken === 'string' && typeof baseUrl === 'string') { if (typeof accessToken === 'string' && typeof baseUrl === 'string') {
sessions.set(clientId, { accessToken, baseUrl }); sessions.set(clientId, { accessToken, baseUrl });
} else { } else {