Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Conform more of the codebase to strictNullChecks #10573

Merged
merged 2 commits into from
Apr 13, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions src/ImageUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,16 @@ limitations under the License.
* consume in the timeline, when performing scroll offset calculations
* (e.g. scroll locking)
*/
export function thumbHeight(fullWidth: number, fullHeight: number, thumbWidth: number, thumbHeight: number): number;
export function thumbHeight(
fullWidth: number,
fullHeight: number,
fullWidth: number | undefined,
fullHeight: number | undefined,
thumbWidth: number,
thumbHeight: number,
): null;
export function thumbHeight(
fullWidth: number | undefined,
fullHeight: number | undefined,
thumbWidth: number,
thumbHeight: number,
): number | null {
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/AutoHideScrollbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type DynamicHtmlElementProps<T extends keyof JSX.IntrinsicElements> =
type DynamicElementProps<T extends keyof JSX.IntrinsicElements> = Partial<Omit<JSX.IntrinsicElements[T], "ref">>;

export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<DynamicHtmlElementProps<T>, "onScroll"> & {
element?: T;
element: T;
className?: string;
onScroll?: (event: Event) => void;
onWheel?: (event: WheelEvent) => void;
Expand Down
3 changes: 2 additions & 1 deletion src/components/structures/IndicatorScrollbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ import React, { createRef } from "react";
import AutoHideScrollbar, { IProps as AutoHideScrollbarProps } from "./AutoHideScrollbar";
import UIStore, { UI_EVENTS } from "../../stores/UIStore";

export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<AutoHideScrollbarProps<T>, "onWheel"> & {
export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<AutoHideScrollbarProps<T>, "onWheel" | "element"> & {
element?: T;
// If true, the scrollbar will append mx_IndicatorScrollbar_leftOverflowIndicator
// and mx_IndicatorScrollbar_rightOverflowIndicator elements to the list for positioning
// by the parent element.
Expand Down
10 changes: 6 additions & 4 deletions src/components/structures/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -90,11 +90,13 @@ export default class LeftPanel extends React.Component<IProps, IState> {
}

public componentDidMount(): void {
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
if (this.listContainerRef.current) {
UIStore.instance.trackElementDimensions("ListContainer", this.listContainerRef.current);
// Using the passive option to not block the main thread
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
this.listContainerRef.current.addEventListener("scroll", this.onScroll, { passive: true });
}
UIStore.instance.on("ListContainer", this.refreshStickyHeaders);
// Using the passive option to not block the main thread
// https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#improving_scrolling_performance_with_passive_listeners
this.listContainerRef.current?.addEventListener("scroll", this.onScroll, { passive: true });
}

public componentWillUnmount(): void {
Expand Down
4 changes: 2 additions & 2 deletions src/components/structures/LegacyCallEventGrouper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -177,9 +177,9 @@ export default class LegacyCallEventGrouper extends EventEmitter {
}

private setState = (): void => {
if (CONNECTING_STATES.includes(this.call?.state)) {
if (this.call && CONNECTING_STATES.includes(this.call.state)) {
this.state = CallState.Connecting;
} else if (SUPPORTED_STATES.includes(this.call?.state)) {
} else if (this.call && SUPPORTED_STATES.includes(this.call.state)) {
this.state = this.call.state;
} else {
if (this.callWasMissed) this.state = CustomCallState.Missed;
Expand Down
17 changes: 9 additions & 8 deletions src/components/structures/MatrixChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -471,11 +471,9 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
);
}, 1000);

private getFallbackHsUrl(): string | null {
private getFallbackHsUrl(): string | undefined {
if (this.props.serverConfig?.isDefault) {
return this.props.config.fallback_hs_url ?? null;
} else {
return null;
return this.props.config.fallback_hs_url;
}
}

Expand Down Expand Up @@ -577,7 +575,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
if (payload.event_type === "m.identity_server") {
const fullUrl = payload.event_content ? payload.event_content["base_url"] : null;
if (!fullUrl) {
MatrixClientPeg.get().setIdentityServerUrl(null);
MatrixClientPeg.get().setIdentityServerUrl(undefined);
localStorage.removeItem("mx_is_access_token");
localStorage.removeItem("mx_is_url");
} else {
Expand Down Expand Up @@ -1229,6 +1227,10 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
* @returns {string} The room ID of the new room, or null if no room was created
*/
private async startWelcomeUserChat(): Promise<string | null> {
const snakedConfig = new SnakedObject<IConfigOptions>(this.props.config);
const welcomeUserId = snakedConfig.get("welcome_user_id");
if (!welcomeUserId) return null;

// We can end up with multiple tabs post-registration where the user
// might then end up with a session and we don't want them all making
// a chat with the welcome user: try to de-dupe.
Expand All @@ -1242,8 +1244,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
}
await waitFor;

const snakedConfig = new SnakedObject<IConfigOptions>(this.props.config);
const welcomeUserRooms = DMRoomMap.shared().getDMRoomsForUserId(snakedConfig.get("welcome_user_id"));
const welcomeUserRooms = DMRoomMap.shared().getDMRoomsForUserId(welcomeUserId);
if (welcomeUserRooms.length === 0) {
const roomId = await createRoom({
dmUserId: snakedConfig.get("welcome_user_id"),
Expand All @@ -1260,7 +1261,7 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
// user room (it doesn't wait for new data from the server, just
// the saved sync to be loaded).
const saveWelcomeUser = (ev: MatrixEvent): void => {
if (ev.getType() === EventType.Direct && ev.getContent()[snakedConfig.get("welcome_user_id")]) {
if (ev.getType() === EventType.Direct && ev.getContent()[welcomeUserId]) {
MatrixClientPeg.get().store.save(true);
MatrixClientPeg.get().removeListener(ClientEvent.AccountData, saveWelcomeUser);
}
Expand Down
10 changes: 3 additions & 7 deletions src/components/structures/MessagePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -869,7 +869,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
const receiptsByEvent: Map<string, IReadReceiptProps[]> = new Map();
const receiptsByUserId: Map<string, IReadReceiptForUser> = new Map();

let lastShownEventId: string;
let lastShownEventId: string | undefined;
for (const event of this.props.events) {
if (this.shouldShowEvent(event)) {
lastShownEventId = event.getId();
Expand Down Expand Up @@ -1018,11 +1018,7 @@ export default class MessagePanel extends React.Component<IProps, IState> {
let ircResizer: JSX.Element | undefined;
if (this.props.layout == Layout.IRC) {
ircResizer = (
<IRCTimelineProfileResizer
minWidth={20}
maxWidth={600}
roomId={this.props.room ? this.props.room.roomId : null}
/>
<IRCTimelineProfileResizer minWidth={20} maxWidth={600} roomId={this.props.room?.roomId ?? null} />
);
}

Expand Down Expand Up @@ -1206,7 +1202,7 @@ class CreationGrouper extends BaseGrouper {
let summaryText: string;
const roomId = ev.getRoomId();
const creator = ev.sender?.name ?? ev.getSender();
if (DMRoomMap.shared().getUserIdForRoomId(roomId)) {
if (roomId && DMRoomMap.shared().getUserIdForRoomId(roomId)) {
summaryText = _t("%(creator)s created this DM.", { creator });
} else {
summaryText = _t("%(creator)s created and configured the room.", { creator });
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/RightPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ export default class RightPanel extends React.Component<IProps, IState> {
// When the user clicks close on the encryption panel cancel the pending request first if any
this.state.cardState.verificationRequest.cancel();
} else {
RightPanelStore.instance.togglePanel(this.props.room?.roomId);
RightPanelStore.instance.togglePanel(this.props.room?.roomId ?? null);
}
};

Expand Down
1 change: 1 addition & 0 deletions src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1597,6 +1597,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
};

private injectSticker(url: string, info: object, text: string, threadId: string | null): void {
if (!this.context.client) return;
if (this.context.client.isGuest()) {
dis.dispatch({ action: "require_registration" });
return;
Expand Down
4 changes: 2 additions & 2 deletions src/components/structures/ScrollPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ export default class ScrollPanel extends React.Component<IProps> {
// Is that next fill request scheduled because of a props update?
private pendingFillDueToPropsUpdate: boolean;
private scrollState: IScrollState;
private preventShrinkingState: IPreventShrinkingState;
private preventShrinkingState: IPreventShrinkingState | null;
private unfillDebouncer: number | null;
private bottomGrowth: number;
private minListHeight: number;
Expand Down Expand Up @@ -676,7 +676,7 @@ export default class ScrollPanel extends React.Component<IProps> {
debuglog("unable to save scroll state: found no children in the viewport");
return;
}
const scrollToken = node!.dataset.scrollTokens.split(",")[0];
const scrollToken = node!.dataset.scrollTokens?.split(",")[0];
debuglog("saving anchored scroll state to message", scrollToken);
const bottomOffset = this.topFromBottom(node);
this.scrollState = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/auth/Registration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const debuglog = (...args: any[]): void => {

interface IProps {
serverConfig: ValidatedServerConfig;
defaultDeviceDisplayName: string;
defaultDeviceDisplayName?: string;
email?: string;
brand?: string;
clientSecret?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const ConfirmSpaceUserActionDialog: React.FC<IProps> = ({
const [roomsToLeave, setRoomsToLeave] = useState<Room[]>([]);
const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]);

let warning: JSX.Element;
let warning: JSX.Element | undefined;
if (warningMessage) {
warning = <div className="mx_ConfirmSpaceUserActionDialog_warning">{warningMessage}</div>;
}
Expand Down
6 changes: 3 additions & 3 deletions src/components/views/dialogs/CreateSubspaceDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/

import React, { useRef, useState } from "react";
import React, { RefObject, useRef, useState } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
import { logger } from "matrix-js-sdk/src/logger";
Expand All @@ -41,9 +41,9 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick

const [busy, setBusy] = useState<boolean>(false);
const [name, setName] = useState("");
const spaceNameField = useRef<Field>();
const spaceNameField = useRef() as RefObject<Field>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to cast it ? An issue between MutableRefObject and RefObject ?

Copy link
Member Author

@t3chguy t3chguy Apr 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, plus we don't really want to encourage manual mutation, it should be managed entirely by React and only accessed by us. But yeah without it React + Typescript don't fit the type properly

image

For some reason MutableRefObject always allows undefined - RefObject always null - things don't seem quite right

const [alias, setAlias] = useState("");
const spaceAliasField = useRef<RoomAliasField>();
const spaceAliasField = useRef() as RefObject<RoomAliasField>;
const [avatar, setAvatar] = useState<File | undefined>();
const [topic, setTopic] = useState<string>("");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import AccessibleButton from "../elements/AccessibleButton";
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
import StyledCheckbox from "../elements/StyledCheckbox";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import { filterBoolean } from "../../../utils/arrays";

interface IProps {
room: Room;
Expand Down Expand Up @@ -65,7 +66,7 @@ const Entry: React.FC<{
)}
</div>
<StyledCheckbox
onChange={onChange ? (e) => onChange(e.target.checked) : null}
onChange={onChange ? (e) => onChange(e.target.checked) : undefined}
checked={checked}
disabled={!onChange}
/>
Expand All @@ -80,7 +81,7 @@ const addAllParents = (set: Set<Room>, room: Room): void => {
);

parents.forEach((parent) => {
if (set.has(parent)) return;
if (!parent || set.has(parent)) return;
set.add(parent);
addAllParents(set, parent);
});
Expand All @@ -97,17 +98,17 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
addAllParents(parents, room);
return [
Array.from(parents),
selected
.map((roomId) => {
filterBoolean(
selected.map((roomId) => {
const room = cli.getRoom(roomId);
if (!room) {
return { roomId, name: roomId } as Room;
}
if (room.getMyMembership() !== "join" || !room.isSpaceRoom()) {
return room;
}
})
.filter(Boolean),
}),
),
];
}, [cli, selected, room]);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ limitations under the License.
*/

import * as React from "react";
import { SyntheticEvent, useRef, useState } from "react";
import { RefObject, SyntheticEvent, useRef, useState } from "react";

import { _t, _td } from "../../../languageHandler";
import Field from "../elements/Field";
Expand All @@ -30,7 +30,7 @@ interface IProps {

const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
const [email, setEmail] = useState("");
const fieldRef = useRef<Field>();
const fieldRef = useRef() as RefObject<Field>;

const onSubmit = async (e: SyntheticEvent): Promise<void> => {
e.preventDefault();
Expand Down
4 changes: 2 additions & 2 deletions src/components/views/dialogs/spotlight/SpotlightDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -288,8 +288,8 @@ interface IDirectoryOpts {
}

const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = null, onFinished }) => {
const inputRef = useRef<HTMLInputElement>();
const scrollContainerRef = useRef<HTMLDivElement>();
const inputRef = useRef() as RefObject<HTMLInputElement>;
const scrollContainerRef = useRef() as RefObject<HTMLDivElement>;
const cli = MatrixClientPeg.get();
const rovingContext = useContext(RovingTabIndexContext);
const [query, _setQuery] = useState(initialText);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ interface IProps {
// The text to show as the summary of this event list
"summaryText"?: ReactNode;
// An array of EventTiles to render when expanded
"children": ReactNode[];
"children": ReactNode[] | null;
// Called when the event list expansion is toggled
onToggle?(): void;
// The layout currently used
Expand Down
18 changes: 10 additions & 8 deletions src/components/views/rooms/AppsDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,11 @@ interface IProps {
}

interface IState {
apps: Partial<{ [id in Container]: IApp[] }>;
apps: {
[Container.Top]: IApp[];
[Container.Center]: IApp[];
[Container.Right]?: IApp[];
};
resizingVertical: boolean; // true when changing the height of the apps drawer
resizingHorizontal: boolean; // true when changing the distribution of the width between widgets
resizing: boolean;
Expand Down Expand Up @@ -203,12 +207,10 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
}
};

private getApps = (): Partial<{ [id in Container]: IApp[] }> => {
const appsDict: Partial<{ [id in Container]: IApp[] }> = {};
appsDict[Container.Top] = WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Top);
appsDict[Container.Center] = WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Center);
return appsDict;
};
private getApps = (): IState["apps"] => ({
[Container.Top]: WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Top),
[Container.Center]: WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Center),
});
private topApps = (): IApp[] => this.state.apps[Container.Top];
private centerApps = (): IApp[] => this.state.apps[Container.Center];

Expand Down Expand Up @@ -348,7 +350,7 @@ const PersistentVResizer: React.FC<IPersistentResizerProps> = ({
resizeNotifier.notifyTimelineHeightChanged();
}}
onResizeStop={(e, dir, ref, d) => {
let newHeight = defaultHeight + d.height;
let newHeight = defaultHeight! + d.height;
newHeight = percentageOf(newHeight, minHeight, maxHeight) * 100;

WidgetLayoutStore.instance.setContainerHeight(room, Container.Top, newHeight);
Expand Down
Loading