Skip to content

Commit 0130443

Browse files
authored
Make tsc faster again (#28678)
* Stash initial work to bring TSC from over 6 mins to under 1 minute Signed-off-by: Michael Telatynski <[email protected]> * Stabilise types Signed-off-by: Michael Telatynski <[email protected]> * Fix incorrect props to AccessibleButton Signed-off-by: Michael Telatynski <[email protected]> * Swap AccessibleButton element types to match the props they provide Signed-off-by: Michael Telatynski <[email protected]> * Changed my mind, remove spurious previously ignored props Signed-off-by: Michael Telatynski <[email protected]> * Update snapshots Signed-off-by: Michael Telatynski <[email protected]> --------- Signed-off-by: Michael Telatynski <[email protected]>
1 parent c659afa commit 0130443

File tree

24 files changed

+83
-111
lines changed

24 files changed

+83
-111
lines changed

src/accessibility/context_menu/ContextMenuButton.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,25 +8,24 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
88
Please see LICENSE files in the repository root for full details.
99
*/
1010

11-
import React, { ComponentProps, forwardRef, Ref } from "react";
11+
import React, { forwardRef, Ref } from "react";
1212

13-
import AccessibleButton from "../../components/views/elements/AccessibleButton";
13+
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
1414

15-
type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
15+
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
1616
label?: string;
1717
// whether the context menu is currently open
1818
isExpanded: boolean;
1919
};
2020

2121
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
22-
export const ContextMenuButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
23-
{ label, isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
24-
ref: Ref<HTMLElement>,
22+
export const ContextMenuButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
23+
{ label, isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
24+
ref: Ref<HTMLElementTagNameMap[T]>,
2525
) {
2626
return (
2727
<AccessibleButton
2828
{...props}
29-
element={element as keyof JSX.IntrinsicElements}
3029
onClick={onClick}
3130
onContextMenu={onContextMenu ?? onClick ?? undefined}
3231
aria-label={label}

src/accessibility/context_menu/ContextMenuTooltipButton.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,24 +8,23 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
88
Please see LICENSE files in the repository root for full details.
99
*/
1010

11-
import React, { ComponentProps, forwardRef, Ref } from "react";
11+
import React, { forwardRef, Ref } from "react";
1212

13-
import AccessibleButton from "../../components/views/elements/AccessibleButton";
13+
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
1414

15-
type Props<T extends keyof JSX.IntrinsicElements> = ComponentProps<typeof AccessibleButton<T>> & {
15+
type Props<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
1616
// whether the context menu is currently open
1717
isExpanded: boolean;
1818
};
1919

2020
// Semantic component for representing the AccessibleButton which launches a <ContextMenu />
21-
export const ContextMenuTooltipButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
22-
{ isExpanded, children, onClick, onContextMenu, element, ...props }: Props<T>,
23-
ref: Ref<HTMLElement>,
21+
export const ContextMenuTooltipButton = forwardRef(function <T extends keyof HTMLElementTagNameMap>(
22+
{ isExpanded, children, onClick, onContextMenu, ...props }: Props<T>,
23+
ref: Ref<HTMLElementTagNameMap[T]>,
2424
) {
2525
return (
2626
<AccessibleButton
2727
{...props}
28-
element={element as keyof JSX.IntrinsicElements}
2928
onClick={onClick}
3029
onContextMenu={onContextMenu ?? onClick ?? undefined}
3130
aria-haspopup={true}

src/accessibility/roving/RovingAccessibleButton.tsx

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,33 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
66
Please see LICENSE files in the repository root for full details.
77
*/
88

9-
import React, { ComponentProps } from "react";
9+
import React, { RefObject } from "react";
1010

11-
import AccessibleButton from "../../components/views/elements/AccessibleButton";
11+
import AccessibleButton, { ButtonProps } from "../../components/views/elements/AccessibleButton";
1212
import { useRovingTabIndex } from "../RovingTabIndex";
13-
import { Ref } from "./types";
1413

15-
type Props<T extends keyof JSX.IntrinsicElements> = Omit<
16-
ComponentProps<typeof AccessibleButton<T>>,
17-
"inputRef" | "tabIndex"
18-
> & {
19-
inputRef?: Ref;
14+
type Props<T extends keyof HTMLElementTagNameMap> = Omit<ButtonProps<T>, "tabIndex"> & {
15+
inputRef?: RefObject<HTMLElementTagNameMap[T]>;
2016
focusOnMouseOver?: boolean;
2117
};
2218

2319
// Wrapper to allow use of useRovingTabIndex for simple AccessibleButtons outside of React Functional Components.
24-
export const RovingAccessibleButton = <T extends keyof JSX.IntrinsicElements>({
20+
export const RovingAccessibleButton = <T extends keyof HTMLElementTagNameMap>({
2521
inputRef,
2622
onFocus,
2723
onMouseOver,
2824
focusOnMouseOver,
29-
element,
3025
...props
3126
}: Props<T>): JSX.Element => {
32-
const [onFocusInternal, isActive, ref] = useRovingTabIndex(inputRef);
27+
const [onFocusInternal, isActive, ref] = useRovingTabIndex<HTMLElementTagNameMap[T]>(inputRef);
3328
return (
3429
<AccessibleButton
3530
{...props}
36-
element={element as keyof JSX.IntrinsicElements}
37-
onFocus={(event: React.FocusEvent) => {
31+
onFocus={(event: React.FocusEvent<never, never>) => {
3832
onFocusInternal();
3933
onFocus?.(event);
4034
}}
41-
onMouseOver={(event: React.MouseEvent) => {
35+
onMouseOver={(event: React.MouseEvent<never, never>) => {
4236
if (focusOnMouseOver) onFocusInternal();
4337
onMouseOver?.(event);
4438
}}

src/components/structures/auth/SoftLogout.tsx

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -235,12 +235,7 @@ export default class SoftLogout extends React.Component<IProps, IState> {
235235
value={this.state.password}
236236
disabled={this.state.busy}
237237
/>
238-
<AccessibleButton
239-
onClick={this.onPasswordLogin}
240-
kind="primary"
241-
type="submit"
242-
disabled={this.state.busy}
243-
>
238+
<AccessibleButton onClick={this.onPasswordLogin} kind="primary" disabled={this.state.busy}>
244239
{_t("action|sign_in")}
245240
</AccessibleButton>
246241
<AccessibleButton onClick={this.onForgotPassword} kind="link">

src/components/views/auth/InteractiveAuthEntryComponents.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -910,7 +910,7 @@ export class SSOAuthEntry extends React.Component<ISSOAuthEntryProps, ISSOAuthEn
910910

911911
export class FallbackAuthEntry<T = {}> extends React.Component<IAuthEntryProps & T> {
912912
protected popupWindow: Window | null;
913-
protected fallbackButton = createRef<HTMLButtonElement>();
913+
protected fallbackButton = createRef<HTMLDivElement>();
914914

915915
public constructor(props: IAuthEntryProps & T) {
916916
super(props);

src/components/views/dialogs/devtools/SettingExplorer.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ const SettingsList: React.FC<ISettingsListProps> = ({ onBack, onView, onEdit })
298298
<code>{i}</code>
299299
</AccessibleButton>
300300
<AccessibleButton
301-
alt={_t("devtools|edit_setting")}
301+
title={_t("devtools|edit_setting")}
302302
onClick={() => onEdit(i)}
303303
className="mx_DevTools_SettingsExplorer_edit"
304304
>

src/components/views/dialogs/spotlight/SpotlightDialog.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
12531253
<span>{filterToLabel(filter)}</span>
12541254
<AccessibleButton
12551255
tabIndex={-1}
1256-
alt={_t("spotlight_dialog|remove_filter", {
1256+
title={_t("spotlight_dialog|remove_filter", {
12571257
filter: filterToLabel(filter),
12581258
})}
12591259
className="mx_SpotlightDialog_filter--close"

src/components/views/dialogs/spotlight/TooltipOption.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ import { useRovingTabIndex } from "../../../../accessibility/RovingTabIndex";
1313
import AccessibleButton, { ButtonProps } from "../../elements/AccessibleButton";
1414
import { Ref } from "../../../../accessibility/roving/types";
1515

16-
type TooltipOptionProps<T extends keyof JSX.IntrinsicElements> = ButtonProps<T> & {
16+
type TooltipOptionProps<T extends keyof HTMLElementTagNameMap> = ButtonProps<T> & {
17+
className?: string;
1718
endAdornment?: ReactNode;
1819
inputRef?: Ref;
1920
};
2021

21-
export const TooltipOption = <T extends keyof JSX.IntrinsicElements>({
22+
export const TooltipOption = <T extends keyof HTMLElementTagNameMap>({
2223
inputRef,
2324
className,
24-
element,
2525
...props
2626
}: TooltipOptionProps<T>): JSX.Element => {
2727
const [onFocus, isActive, ref] = useRovingTabIndex(inputRef);
@@ -34,7 +34,6 @@ export const TooltipOption = <T extends keyof JSX.IntrinsicElements>({
3434
tabIndex={-1}
3535
aria-selected={isActive}
3636
role="option"
37-
element={element as keyof JSX.IntrinsicElements}
3837
/>
3938
);
4039
};

src/components/views/directory/NetworkDropdown.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@ export const NetworkDropdown: React.FC<IProps> = ({ protocols, config, setConfig
168168
adornment: (
169169
<AccessibleButton
170170
className="mx_NetworkDropdown_removeServer"
171-
alt={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
171+
title={_t("spotlight|public_rooms|network_dropdown_remove_server_adornment", { roomServer })}
172172
onClick={() => setUserDefinedServers(without(userDefinedServers, roomServer))}
173173
/>
174174
),

src/components/views/elements/AccessibleButton.tsx

Lines changed: 34 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,15 @@ SPDX-License-Identifier: AGPL-3.0-only OR GPL-3.0-only
66
Please see LICENSE files in the repository root for full details.
77
*/
88

9-
import React, { ComponentProps, forwardRef, FunctionComponent, HTMLAttributes, InputHTMLAttributes, Ref } from "react";
9+
import React, {
10+
ComponentProps,
11+
ComponentPropsWithoutRef,
12+
forwardRef,
13+
FunctionComponent,
14+
ReactElement,
15+
KeyboardEvent,
16+
Ref,
17+
} from "react";
1018
import classnames from "classnames";
1119
import { Tooltip } from "@vector-im/compound-web";
1220

@@ -38,20 +46,8 @@ export type AccessibleButtonKind =
3846
| "icon_primary"
3947
| "icon_primary_outline";
4048

41-
/**
42-
* This type construct allows us to specifically pass those props down to the element we’re creating that the element
43-
* actually supports.
44-
*
45-
* e.g., if element is set to "a", we’ll support href and target, if it’s set to "input", we support type.
46-
*
47-
* To remain compatible with existing code, we’ll continue to support InputHTMLAttributes<Element>
48-
*/
49-
type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
50-
JSX.IntrinsicElements[T] extends HTMLAttributes<{}> ? DynamicElementProps<T> : DynamicElementProps<"div">;
51-
type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<
52-
Omit<JSX.IntrinsicElements[T], "ref" | "onClick" | "onMouseDown" | "onKeyUp" | "onKeyDown">
53-
> &
54-
Omit<InputHTMLAttributes<Element>, "onClick">;
49+
type ElementType = keyof HTMLElementTagNameMap;
50+
const defaultElement = "div";
5551

5652
type TooltipProps = ComponentProps<typeof Tooltip>;
5753

@@ -60,7 +56,7 @@ type TooltipProps = ComponentProps<typeof Tooltip>;
6056
*
6157
* Extends props accepted by the underlying element specified using the `element` prop.
6258
*/
63-
type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> & {
59+
type Props<T extends ElementType = "div"> = {
6460
/**
6561
* The base element type. "div" by default.
6662
*/
@@ -105,14 +101,12 @@ type Props<T extends keyof JSX.IntrinsicElements> = DynamicHtmlElementProps<T> &
105101
disableTooltip?: TooltipProps["disabled"];
106102
};
107103

108-
export type ButtonProps<T extends keyof JSX.IntrinsicElements> = Props<T>;
104+
export type ButtonProps<T extends ElementType> = Props<T> & Omit<ComponentPropsWithoutRef<T>, keyof Props<T>>;
109105

110106
/**
111107
* Type of the props passed to the element that is rendered by AccessibleButton.
112108
*/
113-
interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
114-
ref?: React.Ref<Element>;
115-
}
109+
type RenderedElementProps<T extends ElementType> = React.InputHTMLAttributes<Element> & RefProp<T>;
116110

117111
/**
118112
* AccessibleButton is a generic wrapper for any element that should be treated
@@ -124,9 +118,9 @@ interface RenderedElementProps extends React.InputHTMLAttributes<Element> {
124118
* @param {Object} props react element properties
125119
* @returns {Object} rendered react
126120
*/
127-
const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicElements>(
121+
const AccessibleButton = forwardRef(function <T extends ElementType = typeof defaultElement>(
128122
{
129-
element = "div" as T,
123+
element,
130124
onClick,
131125
children,
132126
kind,
@@ -141,10 +135,10 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
141135
onTooltipOpenChange,
142136
disableTooltip,
143137
...restProps
144-
}: Props<T>,
145-
ref: Ref<HTMLElement>,
138+
}: ButtonProps<T>,
139+
ref: Ref<HTMLElementTagNameMap[T]>,
146140
): JSX.Element {
147-
const newProps: RenderedElementProps = restProps;
141+
const newProps = restProps as RenderedElementProps<T>;
148142
newProps["aria-label"] = newProps["aria-label"] ?? title;
149143
if (disabled) {
150144
newProps["aria-disabled"] = true;
@@ -162,7 +156,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
162156
// And divs which we report as role button to assistive technologies.
163157
// Browsers handle space and enter key presses differently and we are only adjusting to the
164158
// inconsistencies here
165-
newProps.onKeyDown = (e) => {
159+
newProps.onKeyDown = (e: KeyboardEvent<never>) => {
166160
const action = getKeyBindingsManager().getAccessibilityAction(e);
167161

168162
switch (action) {
@@ -178,7 +172,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
178172
onKeyDown?.(e);
179173
}
180174
};
181-
newProps.onKeyUp = (e) => {
175+
newProps.onKeyUp = (e: KeyboardEvent<never>) => {
182176
const action = getKeyBindingsManager().getAccessibilityAction(e);
183177

184178
switch (action) {
@@ -207,7 +201,7 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
207201
});
208202

209203
// React.createElement expects InputHTMLAttributes
210-
const button = React.createElement(element, newProps, children);
204+
const button = React.createElement(element ?? defaultElement, newProps, children);
211205

212206
if (title) {
213207
return (
@@ -233,4 +227,15 @@ const AccessibleButton = forwardRef(function <T extends keyof JSX.IntrinsicEleme
233227
};
234228
(AccessibleButton as FunctionComponent).displayName = "AccessibleButton";
235229

236-
export default AccessibleButton;
230+
interface RefProp<T extends ElementType> {
231+
ref?: Ref<HTMLElementTagNameMap[T]>;
232+
}
233+
234+
interface ButtonComponent {
235+
// With the explicit `element` prop
236+
<C extends ElementType>(props: { element?: C } & ButtonProps<C> & RefProp<C>): ReactElement;
237+
// Without the explicit `element` prop
238+
(props: ButtonProps<"div"> & RefProp<"div">): ReactElement;
239+
}
240+
241+
export default AccessibleButton as ButtonComponent;

0 commit comments

Comments
 (0)