diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx index 89e9d76629..32ef26aaf0 100644 --- a/src/HtmlUtils.tsx +++ b/src/HtmlUtils.tsx @@ -466,7 +466,7 @@ const emojiToJsxSpan = (emoji: string, key: number): JSX.Element => ( */ export function formatEmojis(message: string | undefined, isHtmlMessage?: false): JSX.Element[]; export function formatEmojis(message: string | undefined, isHtmlMessage: true): string[]; -export function formatEmojis(message: string | undefined, isHtmlMessage: boolean): (JSX.Element | string)[] { +export function formatEmojis(message: string | undefined, isHtmlMessage?: boolean): (JSX.Element | string)[] { const emojiToSpan = isHtmlMessage ? emojiToHtmlSpan : emojiToJsxSpan; const result: (JSX.Element | string)[] = []; if (!message) return result; diff --git a/src/ScalarMessaging.ts b/src/ScalarMessaging.ts index b3a0c5640b..e500c34828 100644 --- a/src/ScalarMessaging.ts +++ b/src/ScalarMessaging.ts @@ -626,7 +626,7 @@ async function setBotPower( success: true, }); } catch (err) { - sendError(event, err.message ? err.message : _t("Failed to send request."), err); + sendError(event, err instanceof Error ? err.message : _t("Failed to send request."), err); } } diff --git a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx index d07c86daa1..c188319b3a 100644 --- a/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx +++ b/src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx @@ -42,7 +42,7 @@ interface IState { passPhraseConfirm: string; copied: boolean; downloaded: boolean; - error?: string; + error?: boolean; } /* @@ -94,7 +94,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent { this.setState({ rejecting: false, - rejectError: error, }); }, ); @@ -1714,7 +1712,6 @@ export class RoomView extends React.Component { this.setState({ rejecting: false, - rejectError: error, }); } }; diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx index 63022d80c3..0dc31665d2 100644 --- a/src/components/structures/ScrollPanel.tsx +++ b/src/components/structures/ScrollPanel.tsx @@ -491,7 +491,7 @@ export default class ScrollPanel extends React.Component { // This would cause jumping to happen on Chrome/macOS. return new Promise((resolve) => window.setTimeout(resolve, 1)) .then(() => { - return this.props.onFillRequest(backwards); + return this.props.onFillRequest?.(backwards); }) .finally(() => { this.pendingFillRequests[dir] = false; diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index fc9b29d69f..47e53f18ae 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -1623,12 +1623,12 @@ class TimelinePanel extends React.Component { // dialog, let's jump to the end of the timeline. If we weren't, // something has gone badly wrong and rather than causing a loop of // undismissable dialogs, let's just give up. - if (eventId) { + if (eventId && this.props.timelineSet.room) { onFinished = () => { // go via the dispatcher so that the URL is updated dis.dispatch({ action: Action.ViewRoom, - room_id: this.props.timelineSet.room.roomId, + room_id: this.props.timelineSet.room!.roomId, metricsTrigger: undefined, // room doesn't change }); }; @@ -2098,7 +2098,7 @@ class TimelinePanel extends React.Component { // forwards, otherwise if somebody hits the bottom of the loaded // events when viewing historical messages, we get stuck in a loop // of paginating our way through the entire history of the room. - const stickyBottom = !this.timelineWindow.canPaginate(EventTimeline.FORWARDS); + const stickyBottom = !this.timelineWindow?.canPaginate(EventTimeline.FORWARDS); // If the state is PREPARED or CATCHUP, we're still waiting for the js-sdk to sync with // the HS and fetch the latest events, so we are effectively forward paginating. diff --git a/src/components/structures/UserView.tsx b/src/components/structures/UserView.tsx index e9a05880f6..84e5552e60 100644 --- a/src/components/structures/UserView.tsx +++ b/src/components/structures/UserView.tsx @@ -75,7 +75,7 @@ export default class UserView extends React.Component { } catch (err) { Modal.createDialog(ErrorDialog, { title: _t("Could not load user profile"), - description: err && err.message ? err.message : _t("Operation failed"), + description: err instanceof Error ? err.message : _t("Operation failed"), }); this.setState({ loading: false }); return; diff --git a/src/components/views/context_menus/WidgetContextMenu.tsx b/src/components/views/context_menus/WidgetContextMenu.tsx index 8dc6ca62eb..6482b81773 100644 --- a/src/components/views/context_menus/WidgetContextMenu.tsx +++ b/src/components/views/context_menus/WidgetContextMenu.tsx @@ -71,7 +71,7 @@ export const WidgetContextMenu: React.FC = ({ } catch (err) { logger.error("Failed to start livestream", err); // XXX: won't i18n well, but looks like widget api only support 'message'? - const message = err.message || _t("Unable to start audio streaming."); + const message = err instanceof Error ? err.message : _t("Unable to start audio streaming."); Modal.createDialog(ErrorDialog, { title: _t("Failed to start livestream"), description: message, diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index ed706f97c5..6bf30b2914 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -160,7 +160,7 @@ export default class BugReportDialog extends React.Component { if (!this.unmounted) { this.setState({ downloadBusy: false, - downloadProgress: _t("Failed to send logs: ") + `${err.message}`, + downloadProgress: _t("Failed to send logs: ") + `${err instanceof Error ? err.message : ""}`, }); } } diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx index 9989dc5434..40395b9787 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.tsx @@ -16,6 +16,7 @@ limitations under the License. import React from "react"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; +import { HTTPError, MatrixError } from "matrix-js-sdk/src/matrix"; import { _t } from "../../../languageHandler"; import ConfirmRedactDialog from "./ConfirmRedactDialog"; @@ -62,7 +63,13 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent { this.openRequest(); await request.accept(); } catch (err) { - logger.error(err.message); + logger.error(err); } } }; @@ -86,7 +86,7 @@ export default class MKeyVerificationRequest extends React.Component { try { await request.cancel(); } catch (err) { - logger.error(err.message); + logger.error(err); } } }; diff --git a/src/components/views/room_settings/UrlPreviewSettings.tsx b/src/components/views/room_settings/UrlPreviewSettings.tsx index 15d70132e2..35e0a37061 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.tsx +++ b/src/components/views/room_settings/UrlPreviewSettings.tsx @@ -28,14 +28,14 @@ import { Action } from "../../../dispatcher/actions"; import { SettingLevel } from "../../../settings/SettingLevel"; import SettingsFlag from "../elements/SettingsFlag"; import SettingsFieldset from "../settings/SettingsFieldset"; -import AccessibleButton from "../elements/AccessibleButton"; +import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton"; interface IProps { room: Room; } export default class UrlPreviewSettings extends React.Component { - private onClickUserSettings = (e: React.MouseEvent): void => { + private onClickUserSettings = (e: ButtonEvent): void => { e.preventDefault(); e.stopPropagation(); dis.fire(Action.ViewUserSettings); diff --git a/src/components/views/rooms/BasicMessageComposer.tsx b/src/components/views/rooms/BasicMessageComposer.tsx index 7bf01fa3af..1dc6e5f9d8 100644 --- a/src/components/views/rooms/BasicMessageComposer.tsx +++ b/src/components/views/rooms/BasicMessageComposer.tsx @@ -132,7 +132,7 @@ export default class BasicMessageEditor extends React.Component private hasTextSelected = false; private _isCaretAtEnd = false; - private lastCaret: DocumentOffset; + private lastCaret!: DocumentOffset; private lastSelection: ReturnType | null = null; private readonly useMarkdownHandle: string; diff --git a/src/components/views/settings/ProfileSettings.tsx b/src/components/views/settings/ProfileSettings.tsx index f277872c86..986501b54e 100644 --- a/src/components/views/settings/ProfileSettings.tsx +++ b/src/components/views/settings/ProfileSettings.tsx @@ -124,7 +124,7 @@ export default class ProfileSettings extends React.Component<{}, IState> { logger.log("Failed to save profile", err); Modal.createDialog(ErrorDialog, { title: _t("Failed to save your profile"), - description: err && err.message ? err.message : _t("The operation could not be completed"), + description: err instanceof Error ? err.message : _t("The operation could not be completed"), }); } diff --git a/test/settings/handlers/DeviceSettingsHandler-test.ts b/test/settings/handlers/DeviceSettingsHandler-test.ts index ad9eec99e7..ec3bce41f8 100644 --- a/test/settings/handlers/DeviceSettingsHandler-test.ts +++ b/test/settings/handlers/DeviceSettingsHandler-test.ts @@ -66,7 +66,7 @@ describe("DeviceSettingsHandler", () => { afterEach(() => { MatrixClientPeg.get = () => null; - MatrixClientPeg.safeGet = () => null; + MatrixClientPeg.safeGet = () => new MatrixClient({ baseUrl: "foobar" }); }); it("Returns the value for a disabled feature", () => { diff --git a/test/stores/room-list/MessagePreviewStore-test.ts b/test/stores/room-list/MessagePreviewStore-test.ts index 4cefedef95..fb6207ed52 100644 --- a/test/stores/room-list/MessagePreviewStore-test.ts +++ b/test/stores/room-list/MessagePreviewStore-test.ts @@ -208,8 +208,8 @@ describe("MessagePreviewStore", () => { const preview = await store.getPreviewForRoom(room, DefaultTagID.Untagged); expect(preview).toBeDefined(); - expect(preview.isThreadReply).toBe(false); - expect(preview.text).toMatchInlineSnapshot(`"@sender:server reacted 🙃 to First message"`); + expect(preview?.isThreadReply).toBe(false); + expect(preview?.text).toMatchInlineSnapshot(`"@sender:server reacted 🙃 to First message"`); }); it("should generate the correct preview for a reaction on a thread root", async () => { @@ -227,7 +227,7 @@ describe("MessagePreviewStore", () => { const preview = await store.getPreviewForRoom(room, DefaultTagID.Untagged); expect(preview).toBeDefined(); - expect(preview.isThreadReply).toBe(false); - expect(preview.text).toContain("You reacted 🙃 to root event message"); + expect(preview?.isThreadReply).toBe(false); + expect(preview?.text).toContain("You reacted 🙃 to root event message"); }); });