chore(types): fewer any casts; eslint warning ratchet 36 -> 29 (#210)
CI / Build & Quality Checks (pull_request) Successful in 3m23s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 17s
CI / Playwright smoke (e2e) (pull_request) Successful in 18m6s

- Developer tools (send event, state event editor, room account data) and
  setMarkedUnread go through the typed helpers in utils/room and
  utils/accountData (new setRoomAccountData) instead of casting at the
  call site; sendStateEvent accepts a developer-chosen type string.
- SecretStorage passes the key description as the SDK's
  SecretStorageKeyDescription, CallEmbed replies with an IWidgetApiRequest,
  and fillMissingPowers writes through a Record instead of `as any`.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
This commit is contained in:
Lotus CI
2026-10-20 19:49:15 -04:00
co-authored by Claude Opus 5.5
parent ccbafdb147
commit 42040b6412
10 changed files with 36 additions and 16 deletions
+1 -1
View File
@@ -12,7 +12,7 @@
"build": "vite build",
"preview": "vite preview",
"lint": "npm run check:eslint && npm run check:prettier",
"check:eslint": "eslint src/* --max-warnings 36",
"check:eslint": "eslint src/* --max-warnings 29",
"check:prettier": "prettier --check .",
"fix:prettier": "prettier --write .",
"typecheck": "tsc --noEmit",
+9 -2
View File
@@ -1,6 +1,7 @@
import React, { FormEventHandler, useCallback } from 'react';
import { Box, Text, Button, Spinner, color } from 'folds';
import { decodeRecoveryKey, deriveRecoveryKeyFromPassphrase } from 'matrix-js-sdk/lib/crypto-api';
import type { SecretStorageKeyDescription } from 'matrix-js-sdk/lib/secret-storage';
import { PasswordInput } from './password-input';
import {
SecretStorageKeyContent,
@@ -39,7 +40,10 @@ export function SecretStorageRecoveryPassphrase({
bits,
);
const match = await mx.secretStorage.checkKey(decodedRecoveryKey, keyContent as any);
const match = await mx.secretStorage.checkKey(
decodedRecoveryKey,
keyContent as SecretStorageKeyDescription,
);
if (!match) {
throw new Error('Invalid recovery passphrase.');
@@ -132,7 +136,10 @@ export function SecretStorageRecoveryKey({
async (recoveryKey) => {
const decodedRecoveryKey = decodeRecoveryKey(recoveryKey);
const match = await mx.secretStorage.checkKey(decodedRecoveryKey, keyContent as any);
const match = await mx.secretStorage.checkKey(
decodedRecoveryKey,
keyContent as SecretStorageKeyDescription,
);
if (!match) {
throw new Error('Invalid recovery key.');
@@ -30,6 +30,7 @@ import {
AccountDataSubmitCallback,
} from '../../../components/AccountDataEditor';
import { useMatrixClient } from '../../../hooks/useMatrixClient';
import { setRoomAccountData } from '../../../utils/accountData';
type DeveloperToolsProps = {
requestClose: () => void;
@@ -58,8 +59,7 @@ export function DeveloperTools({ requestClose }: DeveloperToolsProps) {
const submitAccountData: AccountDataSubmitCallback = useCallback(
async (type, content) => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
await mx.setRoomAccountData(room.roomId, type as any, content);
await setRoomAccountData(mx, room.roomId, type, content);
},
[mx, room.roomId],
);
@@ -1,5 +1,5 @@
import React, { useCallback, useRef, useState, FormEventHandler, useEffect } from 'react';
import { MatrixError } from 'matrix-js-sdk';
import { IContent, MatrixError } from 'matrix-js-sdk';
import {
Box,
Chip,
@@ -22,6 +22,7 @@ import { useTextAreaCodeEditor } from '../../../hooks/useTextAreaCodeEditor';
import { AsyncStatus, useAsyncCallback } from '../../../hooks/useAsyncCallback';
import { syntaxErrorPosition } from '../../../utils/dom';
import { Cursor } from '../../../plugins/text-area';
import { sendRoomEvent, sendStateEvent } from '../../../utils/room';
const EDITOR_INTENT_SPACE_COUNT = 2;
@@ -51,9 +52,9 @@ export function SendRoomEvent({ type, stateKey, requestClose }: SendRoomEventPro
useCallback(
(evtType, evtStateKey, evtContent) => {
if (typeof evtStateKey === 'string') {
return mx.sendStateEvent(room.roomId, evtType as any, evtContent, evtStateKey);
return sendStateEvent(mx, room.roomId, evtType, evtContent, evtStateKey);
}
return mx.sendEvent(room.roomId, evtType as any, evtContent);
return sendRoomEvent(mx, room.roomId, null, evtType, evtContent as IContent);
},
[mx, room],
),
@@ -31,6 +31,7 @@ import { usePowerLevels } from '../../../hooks/usePowerLevels';
import { useTextAreaCodeEditor } from '../../../hooks/useTextAreaCodeEditor';
import { useRoomCreators } from '../../../hooks/useRoomCreators';
import { useRoomPermissions } from '../../../hooks/useRoomPermissions';
import { sendStateEvent } from '../../../utils/room';
const EDITOR_INTENT_SPACE_COUNT = 2;
@@ -59,7 +60,7 @@ function StateEventEdit({ type, stateKey, content, requestClose }: StateEventEdi
const [submitState, submit] = useAsyncCallback<object, MatrixError, [object]>(
useCallback(
(c) => mx.sendStateEvent(room.roomId, type as any, c, stateKey),
(c) => sendStateEvent(mx, room.roomId, type, c, stateKey),
[mx, room, type, stateKey],
),
);
+1 -1
View File
@@ -46,7 +46,7 @@ const fillMissingPowers = (powerLevels: IPowerLevels): IPowerLevels =>
const keys = Object.keys(DEFAULT_POWER_LEVELS) as unknown as (keyof IPowerLevels)[];
keys.forEach((key) => {
if (draftPl[key] === undefined) {
draftPl[key] = DEFAULT_POWER_LEVELS[key] as any;
(draftPl as Record<string, unknown>)[key] = DEFAULT_POWER_LEVELS[key];
}
});
if (draftPl.notifications && typeof draftPl.notifications.room !== 'number') {
+2 -1
View File
@@ -15,6 +15,7 @@ import {
WidgetApiFromWidgetAction,
WidgetApiToWidgetAction,
WidgetDriver,
IWidgetApiRequest,
} from 'matrix-widget-api';
import { CallWidgetDriver } from './CallWidgetDriver';
import { trimTrailingSlash } from '../../utils/common';
@@ -796,7 +797,7 @@ export class CallEmbed {
const wrapped = (ev: CustomEvent<T>) => {
ev.preventDefault();
// Reply with success so the widget transport doesn't time out waiting for a response
this.call.transport.reply(ev.detail as any, {});
this.call.transport.reply(ev.detail as unknown as IWidgetApiRequest, {});
callback(ev);
};
return this.listenEvent(`action:${type}`, wrapped);
+3 -4
View File
@@ -2,6 +2,7 @@ import { atom, useSetAtom } from 'jotai';
import { MatrixClient, MatrixEvent, Room, RoomEvent, RoomEventHandlerMap } from 'matrix-js-sdk';
import { useEffect } from 'react';
import { AccountDataEvent } from '../../../types/matrix/accountData';
import { setRoomAccountData } from '../../utils/accountData';
// MSC2867 — "mark a room as unread". A per-room account-data flag `{ unread }`.
// Stable type `m.marked_unread`; servers/clients predating the stabilization use
@@ -25,11 +26,9 @@ export const setMarkedUnread = (
unread: boolean,
): Promise<unknown> =>
Promise.all([
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mx.setRoomAccountData(roomId, AccountDataEvent.MarkedUnread as any, { unread }),
setRoomAccountData(mx, roomId, AccountDataEvent.MarkedUnread, { unread }),
// Best-effort mirror for older servers; never fail the primary write on it.
// eslint-disable-next-line @typescript-eslint/no-explicit-any
mx.setRoomAccountData(roomId, UNSTABLE_MARKED_UNREAD as any, { unread }).catch(() => undefined),
setRoomAccountData(mx, roomId, UNSTABLE_MARKED_UNREAD, { unread }).catch(() => undefined),
]);
export const receiptIsMine = (event: MatrixEvent, userId: string): boolean => {
+11
View File
@@ -18,6 +18,17 @@ export function getAccountData<T>(
return event?.getContent() as T | undefined;
}
/** Room account data under a custom or developer-chosen type (same cast). */
export function setRoomAccountData<T>(
mx: MatrixClient,
roomId: string,
eventType: string,
content: T,
): Promise<unknown> {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return (mx as any).setRoomAccountData(roomId, eventType, content);
}
export function setAccountData<T>(
mx: MatrixClient,
eventType: AccountDataEvent | string,
+1 -1
View File
@@ -60,7 +60,7 @@ export const getStateEvents = (room: Room, eventType: StateEvent): MatrixEvent[]
export function sendStateEvent<T extends object>(
mx: MatrixClient,
roomId: string,
eventType: StateEvent,
eventType: StateEvent | string,
content: T,
stateKey = '',
): Promise<ISendEventResponse> {