From 01304439eefb1af1bd169d74bbd745d335368cb8 Mon Sep 17 00:00:00 2001
From: Michael Telatynski <7t3chguy@gmail.com>
Date: Fri, 6 Dec 2024 17:49:32 +0000
Subject: [PATCH] Make tsc faster again (#28678)

* Stash initial work to bring TSC from over 6 mins to under 1 minute

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Stabilise types

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Fix incorrect props to AccessibleButton

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Swap AccessibleButton element types to match the props they provide

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Changed my mind, remove spurious previously ignored props

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

* Update snapshots

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>

---------

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
---
 .../context_menu/ContextMenuButton.tsx        | 13 ++--
 .../context_menu/ContextMenuTooltipButton.tsx | 13 ++--
 .../roving/RovingAccessibleButton.tsx         | 22 +++----
 src/components/structures/auth/SoftLogout.tsx |  7 +--
 .../auth/InteractiveAuthEntryComponents.tsx   |  2 +-
 .../dialogs/devtools/SettingExplorer.tsx      |  2 +-
 .../dialogs/spotlight/SpotlightDialog.tsx     |  2 +-
 .../views/dialogs/spotlight/TooltipOption.tsx |  7 +--
 .../views/directory/NetworkDropdown.tsx       |  2 +-
 .../views/elements/AccessibleButton.tsx       | 63 ++++++++++---------
 .../views/elements/EditableItemList.tsx       |  7 +--
 src/components/views/emojipicker/Emoji.tsx    |  2 +-
 .../views/messages/MPollEndBody.tsx           |  2 +-
 .../views/messages/MessageActionBar.tsx       |  2 +-
 src/components/views/settings/SetIdServer.tsx |  1 -
 .../devices/DeviceExpandDetailsButton.tsx     | 15 ++---
 .../tabs/user/MjolnirUserSettingsTab.tsx      |  8 +--
 .../views/spaces/SpaceBasicSettings.tsx       |  1 -
 src/components/views/spaces/SpacePanel.tsx    |  2 +-
 .../views/spaces/SpaceTreeLevel.tsx           | 14 ++---
 .../LegacyCallView/LegacyCallViewButtons.tsx  |  2 +-
 .../__snapshots__/MatrixChat-test.tsx.snap    |  1 -
 .../settings/SetIntegrationManager-test.tsx   |  2 +-
 .../MjolnirUserSettingsTab-test.tsx.snap      |  2 -
 24 files changed, 83 insertions(+), 111 deletions(-)

diff --git a/src/accessibility/context_menu/ContextMenuButton.tsx b/src/accessibility/context_menu/ContextMenuButton.tsx
index d8c7d912c1b..9d8b5585e3b 100644
--- a/src/accessibility/context_menu/ContextMenuButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuButton.tsx
@@ -8,25 +8,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
 Please see LICENSE files in the repository root for full details.
 */
 
-import React, { ComponentProps, forwardRef, Ref } from "react";
+import React, { forwardRef, Ref } from "react";
 
-import AccessibleButton from "../../components/views/elements/AccessibleButton";
+import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
 
-type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
+type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
     label?: string;
     // whether the context menu is currently open
     isExpanded: boolean;
 };
 
 // Semantic component for representing the AccessibleButton which launches a <ContextMenu />
-export const ContextMenuButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
-    { label, isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
-    ref: Ref<HTMLElement>,
+export const ContextMenuButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
+    { label, isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
+    ref: Ref<HTMLElementTagNameMap[T]>,
 ) {
     return (
         <AccessibleButton
             {...props}
-            element={element as keyof JSX.IntrinsicElements}
             onClick={onClick}
             onContextMenu={onContextMenu ?? onClick ?? undefined}
             aria-label={label}
diff --git a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
index 11437866bd0..80023680838 100644
--- a/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
+++ b/src/accessibility/context_menu/ContextMenuTooltipButton.tsx
@@ -8,24 +8,23 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
 Please see LICENSE files in the repository root for full details.
 */
 
-import React, { ComponentProps, forwardRef, Ref } from "react";
+import React, { forwardRef, Ref } from "react";
 
-import AccessibleButton from "../../components/views/elements/AccessibleButton";
+import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
 
-type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
+type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
     // whether the context menu is currently open
     isExpanded: boolean;
 };
 
 // Semantic component for representing the AccessibleButton which launches a <ContextMenu />
-export const ContextMenuTooltipButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
-    { isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
-    ref: Ref<HTMLElement>,
+export const ContextMenuTooltipButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
+    { isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
+    ref: Ref<HTMLElementTagNameMap[T]>,
 ) {
     return (
         <AccessibleButton
             {...props}
-            element={element as keyof JSX.IntrinsicElements}
             onClick={onClick}
             onContextMenu={onContextMenu ?? onClick ?? undefined}
             aria-haspopup={true}
diff --git a/src/accessibility/roving/RovingAccessibleButton.tsx b/src/accessibility/roving/RovingAccessibleButton.tsx
index f50fb010ae3..b53221e1c99 100644
--- a/src/accessibility/roving/RovingAccessibleButton.tsx
+++ b/src/accessibility/roving/RovingAccessibleButton.tsx
@@ -6,39 +6,33 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
 Please see LICENSE files in the repository root for full details.
 */
 
-import React, { ComponentProps } from "react";
+import React, { RefObject } from "react";
 
-import AccessibleButton from "../../components/views/elements/AccessibleButton";
+import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
 import { useRovingTabIndex } from "../RovingTabIndex";
-import { Ref } from "./types";
 
-type Props<T extends keyof JSX.IntrinsicElements> = Omit<
-    ComponentProps<typeof AccessibleButton<T>>,
-    "inputRef" | "tabIndex"
-> & {
-    inputRef?: Ref;
+type Props<T extends keyof HTMLElementTagNameMap> = Omit<ButtonProps<T>, "tabIndex"> & {
+    inputRef?: RefObject<HTMLElementTagNameMap[T]>;
     focusOnMouseOver?: boolean;
 };
 
 // Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
-export const RovingAccessibleButton = <T extends keyof JSX.IntrinsicElements>({
+export const RovingAccessibleButton = <T extends keyof HTMLElementTagNameMap>({
     inputRef,
     onFocus,
     onMouseOver,
     focusOnMouseOver,
-    element,
     ...props
 }: Props<T>): JSX.Element => {
-    const [onFocusInternal, isActive, ref] = useRovingTabIndex(inputRef);
+    const [onFocusInternal, isActive, ref] = useRovingTabIndex<HTMLElementTagNameMap[T]>(inputRef);
     return (
         <AccessibleButton
             {...props}
-            element={element as keyof JSX.IntrinsicElements}
-            onFocus={(event: React.FocusEvent) => {
+            onFocus={(event: React.FocusEvent<never, never>) => {
                 onFocusInternal();
                 onFocus?.(event);
             }}
-            onMouseOver={(event: React.MouseEvent) => {
+            onMouseOver={(event: React.MouseEvent<never, never>) => {
                 if (focusOnMouseOver) onFocusInternal();
                 onMouseOver?.(event);
             }}
diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx
index db72a0a04bb..9c7a900643e 100644
--- a/src/components/structures/auth/SoftLogout.tsx
+++ b/src/components/structures/auth/SoftLogout.tsx
@@ -235,12 +235,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
                     value={this.state.password}
                     disabled={this.state.busy}
                 />
-                <AccessibleButton
-                    onClick={this.onPasswordLogin}
-                    kind="primary"
-                    type="submit"
-                    disabled={this.state.busy}
-                >
+                <AccessibleButton onClick={this.onPasswordLogin} kind="primary" disabled={this.state.busy}>
                     {_t("action|sign_in")}
                 </AccessibleButton>
                 <AccessibleButton onClick={this.onForgotPassword} kind="link">
diff --git a/src/components/views/auth/InteractiveAuthEntryComponents.tsx b/src/components/views/auth/InteractiveAuthEntryComponents.tsx
index b1360f55604..ae5c07e3483 100644
--- a/src/components/views/auth/InteractiveAuthEntryComponents.tsx
+++ b/src/components/views/auth/InteractiveAuthEntryComponents.tsx
@@ -910,7 +910,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
 
 export class FallbackAuthEntry<T = {}> extends React.Component<IAuthEntryProps & T> {
     protected popupWindow: Window | null;
-    protected fallbackButton = createRef<HTMLButtonElement>();
+    protected fallbackButton = createRef<HTMLDivElement>();
 
     public constructor(props: IAuthEntryProps & T) {
         super(props);
diff --git a/src/components/views/dialogs/devtools/SettingExplorer.tsx b/src/components/views/dialogs/devtools/SettingExplorer.tsx
index ed4b64d870d..ae37fa3e1c9 100644
--- a/src/components/views/dialogs/devtools/SettingExplorer.tsx
+++ b/src/components/views/dialogs/devtools/SettingExplorer.tsx
@@ -298,7 +298,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
                                     <code>{i}</code>
                                 </AccessibleButton>
                                 <AccessibleButton
-                                    alt={_t("devtools|edit_setting")}
+                                    title={_t("devtools|edit_setting")}
                                     onClick={() => onEdit(i)}
                                     className="mx_DevTools_SettingsExplorer_edit"
                                 >
diff --git a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
index 20d6825b9b7..a87b7341e7d 100644
--- a/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
+++ b/src/components/views/dialogs/spotlight/SpotlightDialog.tsx
@@ -1253,7 +1253,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
                             <span>{filterToLabel(filter)}</span>
                             <AccessibleButton
                                 tabIndex={-1}
-                                alt={_t("spotlight_dialog|remove_filter", {
+                                title={_t("spotlight_dialog|remove_filter", {
                                     filter: filterToLabel(filter),
                                 })}
                                 className="mx_SpotlightDialog_filter--close"
diff --git a/src/components/views/dialogs/spotlight/TooltipOption.tsx b/src/components/views/dialogs/spotlight/TooltipOption.tsx
index 1d60fed5b30..ebb0b4cf06e 100644
--- a/src/components/views/dialogs/spotlight/TooltipOption.tsx
+++ b/src/components/views/dialogs/spotlight/TooltipOption.tsx
@@ -13,15 +13,15 @@ import { useRovingTabIndex } from "../../../../accessibility/RovingTabIndex";
 import AccessibleButton, { ButtonProps } from "../../elements/AccessibleButton";
 import { Ref } from "../../../../accessibility/roving/types";
 
-type TooltipOptionProps<T extends keyof JSX.IntrinsicElements> = ButtonProps<T> & {
+type TooltipOptionProps<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
+    className?: string;
     endAdornment?: ReactNode;
     inputRef?: Ref;
 };
 
-export const TooltipOption = <T extends keyof JSX.IntrinsicElements>({
+export const TooltipOption = <T extends keyof HTMLElementTagNameMap>({
     inputRef,
     className,
-    element,
     ...props
 }: TooltipOptionProps<T>): JSX.Element => {
     const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
@@ -34,7 +34,6 @@ export const TooltipOption = <T extends keyof JSX.IntrinsicElements>({
             tabIndex={-1}
             aria-selected={isActive}
             role="option"
-            element={element as keyof JSX.IntrinsicElements}
         />
     );
 };
diff --git a/src/components/views/directory/NetworkDropdown.tsx b/src/components/views/directory/NetworkDropdown.tsx
index 43d123676b0..a1b1986f471 100644
--- a/src/components/views/directory/NetworkDropdown.tsx
+++ b/src/components/views/directory/NetworkDropdown.tsx
@@ -168,7 +168,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
                   adornment: (
                       <AccessibleButton
                           className="mx_NetworkDropdown_removeServer"
-                          alt={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
+                          title={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
                           onClick={() => setUserDefinedServers(without(userDefinedServers, roomServer))}
                       />
                   ),
diff --git a/src/components/views/elements/AccessibleButton.tsx b/src/components/views/elements/AccessibleButton.tsx
index b8b5297384c..8b58f251c36 100644
--- a/src/components/views/elements/AccessibleButton.tsx
+++ b/src/components/views/elements/AccessibleButton.tsx
@@ -6,7 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
 Please see LICENSE files in the repository root for full details.
  */
 
-import React, { ComponentProps, forwardRef, FunctionComponent, HTMLAttributes, InputHTMLAttributes, Ref } from "react";
+import React, {
+    ComponentProps,
+    ComponentPropsWithoutRef,
+    forwardRef,
+    FunctionComponent,
+    ReactElement,
+    KeyboardEvent,
+    Ref,
+} from "react";
 import classnames from "classnames";
 import { Tooltip } from "@vector-im/compound-web";
 
@@ -38,20 +46,8 @@ export type AccessibleButtonKind =
     | "icon_primary"
     | "icon_primary_outline";
 
-/**
- * This type construct allows us to specifically pass those props down to the element we’re creating that the element
- * actually supports.
- *
- * e.g., if element is set to "a", we’ll support href and target, if it’s set to "input", we support type.
- *
- * To remain compatible with existing code, we’ll continue to support InputHTMLAttributes<Element>
- */
-type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
-    JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">;
-type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<
-    Omit<JSX.IntrinsicElements[T], "ref" | "onClick" | "onMouseDown" | "onKeyUp" | "onKeyDown">
-> &
-    Omit<InputHTMLAttributes<Element>, "onClick">;
+type ElementType = keyof HTMLElementTagNameMap;
+const defaultElement = "div";
 
 type TooltipProps = ComponentProps<typeof Tooltip>;
 
@@ -60,7 +56,7 @@ type TooltipProps = ComponentProps<typeof Tooltip>;
  *
  * Extends props accepted by the underlying element specified using the `element` prop.
  */
-type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
+type Props<T extends ElementType = "div"> = {
     /**
      * The base element type. "div" by default.
      */
@@ -105,14 +101,12 @@ type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> &
     disableTooltip?: TooltipProps["disabled"];
 };
 
-export type ButtonProps<T extends keyof JSX.IntrinsicElements> = Props<T>;
+export type ButtonProps<T extends ElementType> = Props<T> & Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>;
 
 /**
  * Type of the props passed to the element that is rendered by AccessibleButton.
  */
-interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
-    ref?: React.Ref<Element>;
-}
+type RenderedElementProps<T extends ElementType> = React.InputHTMLAttributes<Element> & RefProp<T>;
 
 /**
  * AccessibleButton is a generic wrapper for any element that should be treated
@@ -124,9 +118,9 @@ interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
  * @param {Object} props  react element properties
  * @returns {Object} rendered react
  */
-const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
+const AccessibleButton = forwardRef(function <T extends ElementType = typeof defaultElement>(
     {
-        element = "div" as T,
+        element,
         onClick,
         children,
         kind,
@@ -141,10 +135,10 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
         onTooltipOpenChange,
         disableTooltip,
         ...restProps
-    }: Props<T>,
-    ref: Ref<HTMLElement>,
+    }: ButtonProps<T>,
+    ref: Ref<HTMLElementTagNameMap[T]>,
 ): JSX.Element {
-    const newProps: RenderedElementProps = restProps;
+    const newProps = restProps as RenderedElementProps<T>;
     newProps["aria-label"] = newProps["aria-label"] ?? title;
     if (disabled) {
         newProps["aria-disabled"] = true;
@@ -162,7 +156,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
         // And divs which we report as role button to assistive technologies.
         // Browsers handle space and enter key presses differently and we are only adjusting to the
         // inconsistencies here
-        newProps.onKeyDown = (e) => {
+        newProps.onKeyDown = (e: KeyboardEvent<never>) => {
             const action = getKeyBindingsManager().getAccessibilityAction(e);
 
             switch (action) {
@@ -178,7 +172,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
                     onKeyDown?.(e);
             }
         };
-        newProps.onKeyUp = (e) => {
+        newProps.onKeyUp = (e: KeyboardEvent<never>) => {
             const action = getKeyBindingsManager().getAccessibilityAction(e);
 
             switch (action) {
@@ -207,7 +201,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
     });
 
     // React.createElement expects InputHTMLAttributes
-    const button = React.createElement(element, newProps, children);
+    const button = React.createElement(element ?? defaultElement, newProps, children);
 
     if (title) {
         return (
@@ -233,4 +227,15 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
 };
 (AccessibleButton as FunctionComponent).displayName = "AccessibleButton";
 
-export default AccessibleButton;
+interface RefProp<T extends ElementType> {
+    ref?: Ref<HTMLElementTagNameMap[T]>;
+}
+
+interface ButtonComponent {
+    // With the explicit `element` prop
+    <C extends ElementType>(props: { element?: C } & ButtonProps<C> & RefProp<C>): ReactElement;
+    // Without the explicit `element` prop
+    (props: ButtonProps<"div"> & RefProp<"div">): ReactElement;
+}
+
+export default AccessibleButton as ButtonComponent;
diff --git a/src/components/views/elements/EditableItemList.tsx b/src/components/views/elements/EditableItemList.tsx
index dc6e6c09a16..ad2d9aceee7 100644
--- a/src/components/views/elements/EditableItemList.tsx
+++ b/src/components/views/elements/EditableItemList.tsx
@@ -133,12 +133,7 @@ export default class EditableItemList<P = {}> extends React.PureComponent<IProps
                     onChange={this.onNewItemChanged}
                     list={this.props.suggestionsListId}
                 />
-                <AccessibleButton
-                    onClick={this.onItemAdded}
-                    kind="primary"
-                    type="submit"
-                    disabled={!this.props.newItem}
-                >
+                <AccessibleButton onClick={this.onItemAdded} kind="primary" disabled={!this.props.newItem}>
                     {_t("action|add")}
                 </AccessibleButton>
             </form>
diff --git a/src/components/views/emojipicker/Emoji.tsx b/src/components/views/emojipicker/Emoji.tsx
index c3dfb24bd13..a852122b750 100644
--- a/src/components/views/emojipicker/Emoji.tsx
+++ b/src/components/views/emojipicker/Emoji.tsx
@@ -31,7 +31,7 @@ class Emoji extends React.PureComponent<IProps> {
         return (
             <RovingAccessibleButton
                 id={this.props.id}
-                onClick={(ev) => onClick(ev, emoji)}
+                onClick={(ev: ButtonEvent) => onClick(ev, emoji)}
                 onMouseEnter={() => onMouseEnter(emoji)}
                 onMouseLeave={() => onMouseLeave(emoji)}
                 className="mx_EmojiPicker_item_wrapper"
diff --git a/src/components/views/messages/MPollEndBody.tsx b/src/components/views/messages/MPollEndBody.tsx
index 94671fea12e..1129b3538ed 100644
--- a/src/components/views/messages/MPollEndBody.tsx
+++ b/src/components/views/messages/MPollEndBody.tsx
@@ -90,7 +90,7 @@ export const MPollEndBody = React.forwardRef<any, IBodyProps>(({ mxEvent, ...pro
     const { pollStartEvent, isLoadingPollStartEvent } = usePollStartEvent(mxEvent);
 
     if (!pollStartEvent) {
-        const pollEndFallbackMessage = M_TEXT.findIn(mxEvent.getContent()) || textForEvent(mxEvent, cli);
+        const pollEndFallbackMessage = M_TEXT.findIn<string>(mxEvent.getContent()) || textForEvent(mxEvent, cli);
         return (
             <>
                 <PollIcon className="mx_MPollEndBody_icon" />
diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx
index 9d21b8fa45a..579db054e9e 100644
--- a/src/components/views/messages/MessageActionBar.tsx
+++ b/src/components/views/messages/MessageActionBar.tsx
@@ -435,7 +435,7 @@ export default class MessageActionBar extends React.PureComponent<IMessageAction
                 <RovingAccessibleButton
                     className="mx_MessageActionBar_iconButton"
                     title={isPinned ? _t("action|unpin") : _t("action|pin")}
-                    onClick={(e) => this.onPinClick(e, isPinned)}
+                    onClick={(e: ButtonEvent) => this.onPinClick(e, isPinned)}
                     onContextMenu={(e: ButtonEvent) => this.onPinClick(e, isPinned)}
                     key="pin"
                     placement="left"
diff --git a/src/components/views/settings/SetIdServer.tsx b/src/components/views/settings/SetIdServer.tsx
index 8ed6461d0a3..6dc3ae48a2c 100644
--- a/src/components/views/settings/SetIdServer.tsx
+++ b/src/components/views/settings/SetIdServer.tsx
@@ -407,7 +407,6 @@ export default class SetIdServer extends React.Component<IProps, IState> {
                         forceValidity={this.state.error ? false : undefined}
                     />
                     <AccessibleButton
-                        type="submit"
                         kind="primary_sm"
                         onClick={this.checkIdServer}
                         disabled={!this.idServerChangeEnabled()}
diff --git a/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx b/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
index e7839b71da2..a04430a0c23 100644
--- a/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
+++ b/src/components/views/settings/devices/DeviceExpandDetailsButton.tsx
@@ -7,23 +7,21 @@ Please see LICENSE files in the repository root for full details.
 */
 
 import classNames from "classnames";
-import React, { ComponentProps } from "react";
+import React from "react";
 import { ChevronDownIcon } from "@vector-im/compound-design-tokens/assets/web/icons";
 
 import { _t } from "../../../../languageHandler";
-import AccessibleButton from "../../elements/AccessibleButton";
+import AccessibleButton, { ButtonProps } from "../../elements/AccessibleButton";
 
-type Props<T extends keyof JSX.IntrinsicElements> = Omit<
-    ComponentProps<typeof AccessibleButton<T>>,
-    "aria-label" | "title" | "kind" | "className" | "onClick" | "element"
+type Props<T extends keyof HTMLElementTagNameMap> = Omit<
+    ButtonProps<T>,
+    "aria-label" | "title" | "kind" | "className" | "element"
 > & {
     isExpanded: boolean;
-    onClick: () => void;
 };
 
-export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>({
+export const DeviceExpandDetailsButton = <T extends keyof HTMLElementTagNameMap>({
     isExpanded,
-    onClick,
     ...rest
 }: Props<T>): JSX.Element => {
     const label = isExpanded ? _t("settings|sessions|hide_details") : _t("settings|sessions|show_details");
@@ -36,7 +34,6 @@ export const DeviceExpandDetailsButton = <T extends keyof JSX.IntrinsicElements>
             className={classNames("mx_DeviceExpandDetailsButton", {
                 mx_DeviceExpandDetailsButton_expanded: isExpanded,
             })}
-            onClick={onClick}
         >
             <ChevronDownIcon className="mx_DeviceExpandDetailsButton_icon" />
         </AccessibleButton>
diff --git a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
index 9ad7df31e98..3e86d779ff3 100644
--- a/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
+++ b/src/components/views/settings/tabs/user/MjolnirUserSettingsTab.tsx
@@ -268,7 +268,6 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
                                 onChange={this.onPersonalRuleChanged}
                             />
                             <AccessibleButton
-                                type="submit"
                                 kind="primary"
                                 onClick={this.onAddPersonalRule}
                                 disabled={this.state.busy}
@@ -295,12 +294,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
                                 value={this.state.newList}
                                 onChange={this.onNewListChanged}
                             />
-                            <AccessibleButton
-                                type="submit"
-                                kind="primary"
-                                onClick={this.onSubscribeList}
-                                disabled={this.state.busy}
-                            >
+                            <AccessibleButton kind="primary" onClick={this.onSubscribeList} disabled={this.state.busy}>
                                 {_t("action|subscribe")}
                             </AccessibleButton>
                         </form>
diff --git a/src/components/views/spaces/SpaceBasicSettings.tsx b/src/components/views/spaces/SpaceBasicSettings.tsx
index 8311e6728ec..63a70a97cd4 100644
--- a/src/components/views/spaces/SpaceBasicSettings.tsx
+++ b/src/components/views/spaces/SpaceBasicSettings.tsx
@@ -71,7 +71,6 @@ export const SpaceAvatar: React.FC<Pick<IProps, "avatarUrl" | "avatarDisabled" |
                     <AccessibleButton
                         className="mx_SpaceBasicSettings_avatar"
                         onClick={() => avatarUploadRef.current?.click()}
-                        alt=""
                     />
                     <AccessibleButton
                         onClick={() => avatarUploadRef.current?.click()}
diff --git a/src/components/views/spaces/SpacePanel.tsx b/src/components/views/spaces/SpacePanel.tsx
index af484445b42..73bb66af380 100644
--- a/src/components/views/spaces/SpacePanel.tsx
+++ b/src/components/views/spaces/SpacePanel.tsx
@@ -221,7 +221,7 @@ const CreateSpaceButton: React.FC<Pick<IInnerSpacePanelProps, "isPanelCollapsed"
     isPanelCollapsed,
     setPanelCollapsed,
 }) => {
-    const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>();
+    const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
 
     useEffect(() => {
         if (!isPanelCollapsed && menuDisplayed) {
diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx
index cee4cf54ecd..38329c39b73 100644
--- a/src/components/views/spaces/SpaceTreeLevel.tsx
+++ b/src/components/views/spaces/SpaceTreeLevel.tsx
@@ -30,7 +30,7 @@ import defaultDispatcher from "../../../dispatcher/dispatcher";
 import { Action } from "../../../dispatcher/actions";
 import { ContextMenuTooltipButton } from "../../../accessibility/context_menu/ContextMenuTooltipButton";
 import { toRightOf, useContextMenu } from "../../structures/ContextMenu";
-import AccessibleButton, { ButtonEvent } from "../elements/AccessibleButton";
+import AccessibleButton, { ButtonEvent, ButtonProps as AccessibleButtonProps } from "../elements/AccessibleButton";
 import { StaticNotificationState } from "../../../stores/notifications/StaticNotificationState";
 import { NotificationLevel } from "../../../stores/notifications/NotificationLevel";
 import { getKeyBindingsManager } from "../../../KeyBindingsManager";
@@ -39,8 +39,8 @@ import SpaceContextMenu from "../context_menus/SpaceContextMenu";
 import { useRovingTabIndex } from "../../../accessibility/RovingTabIndex";
 import { KeyBindingAction } from "../../../accessibility/KeyboardShortcuts";
 
-type ButtonProps<T extends keyof JSX.IntrinsicElements> = Omit<
-    ComponentProps<typeof AccessibleButton<T>>,
+type ButtonProps<T extends keyof HTMLElementTagNameMap> = Omit<
+    AccessibleButtonProps<T>,
     "title" | "onClick" | "size" | "element"
 > & {
     space?: Room;
@@ -52,12 +52,12 @@ type ButtonProps<T extends keyof JSX.IntrinsicElements> = Omit<
     notificationState?: NotificationState;
     isNarrow?: boolean;
     size: string;
-    innerRef?: RefObject<HTMLElement>;
+    innerRef?: RefObject<HTMLDivElement>;
     ContextMenuComponent?: ComponentType<ComponentProps<typeof SpaceContextMenu>>;
     onClick?(ev?: ButtonEvent): void;
 };
 
-export const SpaceButton = <T extends keyof JSX.IntrinsicElements>({
+export const SpaceButton = <T extends keyof HTMLElementTagNameMap>({
     space,
     spaceKey: _spaceKey,
     className,
@@ -72,8 +72,8 @@ export const SpaceButton = <T extends keyof JSX.IntrinsicElements>({
     ContextMenuComponent,
     ...props
 }: ButtonProps<T>): JSX.Element => {
-    const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLElement>(innerRef);
-    const [onFocus, isActive, ref] = useRovingTabIndex(handle);
+    const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu<HTMLDivElement>(innerRef);
+    const [onFocus, isActive, ref] = useRovingTabIndex<HTMLDivElement>(handle);
     const tabIndex = isActive ? 0 : -1;
 
     const spaceKey = _spaceKey ?? space?.roomId;
diff --git a/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx b/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
index bdcd3713cb5..105736d04e2 100644
--- a/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
+++ b/src/components/views/voip/LegacyCallView/LegacyCallViewButtons.tsx
@@ -69,7 +69,7 @@ interface IDropdownButtonProps extends ButtonProps {
 }
 
 const LegacyCallViewDropdownButton: React.FC<IDropdownButtonProps> = ({ state, deviceKinds, ...props }) => {
-    const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu();
+    const [menuDisplayed, buttonRef, openMenu, closeMenu] = useContextMenu<HTMLDivElement>();
     const [hoveringDropdown, setHoveringDropdown] = useState(false);
 
     const classes = classNames("mx_LegacyCallViewButtons_button", "mx_LegacyCallViewButtons_dropdownButton", {
diff --git a/test/unit-tests/components/structures/__snapshots__/MatrixChat-test.tsx.snap b/test/unit-tests/components/structures/__snapshots__/MatrixChat-test.tsx.snap
index 94c26783886..1bdbe016d41 100644
--- a/test/unit-tests/components/structures/__snapshots__/MatrixChat-test.tsx.snap
+++ b/test/unit-tests/components/structures/__snapshots__/MatrixChat-test.tsx.snap
@@ -314,7 +314,6 @@ exports[`<MatrixChat /> with a soft-logged-out session should show the soft-logo
                 class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
                 role="button"
                 tabindex="0"
-                type="submit"
               >
                 Sign in
               </div>
diff --git a/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx b/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
index 888499d5245..5c77e88d932 100644
--- a/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
+++ b/test/unit-tests/components/views/settings/SetIntegrationManager-test.tsx
@@ -35,7 +35,7 @@ describe("SetIntegrationManager", () => {
         deleteThreePid: jest.fn(),
     });
 
-    let stores: SdkContextClass;
+    let stores!: SdkContextClass;
 
     const getComponent = () => (
         <MatrixClientContext.Provider value={mockClient}>
diff --git a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/MjolnirUserSettingsTab-test.tsx.snap b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/MjolnirUserSettingsTab-test.tsx.snap
index 4bdaf3275c8..17986bd3bcc 100644
--- a/test/unit-tests/components/views/settings/tabs/user/__snapshots__/MjolnirUserSettingsTab-test.tsx.snap
+++ b/test/unit-tests/components/views/settings/tabs/user/__snapshots__/MjolnirUserSettingsTab-test.tsx.snap
@@ -85,7 +85,6 @@ exports[`<MjolnirUserSettingsTab /> renders correctly when user has no ignored u
                   class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
                   role="button"
                   tabindex="0"
-                  type="submit"
                 >
                   Ignore
                 </div>
@@ -150,7 +149,6 @@ exports[`<MjolnirUserSettingsTab /> renders correctly when user has no ignored u
                   class="mx_AccessibleButton mx_AccessibleButton_hasKind mx_AccessibleButton_kind_primary"
                   role="button"
                   tabindex="0"
-                  type="submit"
                 >
                   Subscribe
                 </div>