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 (#10350 #10350

Merged
merged 4 commits into from
Mar 10, 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
2 changes: 2 additions & 0 deletions src/@types/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,5 @@ export type KeysStartingWith<Input extends object, Str extends string> = {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
[P in keyof Input]: P extends `${Str}${infer _X}` ? P : never; // we don't use _X
}[keyof Input];

export type NonEmptyArray<T> = [T, ...T[]];
13 changes: 11 additions & 2 deletions src/AddThreepid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,11 @@ import { SSOAuthEntry } from "./components/views/auth/InteractiveAuthEntryCompon
import InteractiveAuthDialog from "./components/views/dialogs/InteractiveAuthDialog";

function getIdServerDomain(): string {
return MatrixClientPeg.get().idBaseUrl.split("://")[1];
const idBaseUrl = MatrixClientPeg.get().idBaseUrl;
if (!idBaseUrl) {
throw new Error("Identity server not set");
}
return idBaseUrl.split("://")[1];
}

export type Binding = {
Expand Down Expand Up @@ -190,6 +194,9 @@ export default class AddThreepid {
if (this.bind) {
const authClient = new IdentityAuthClient();
const identityAccessToken = await authClient.getAccessToken();
if (!identityAccessToken) {
throw new Error("No identity access token found");
}
await MatrixClientPeg.get().bindThreePid({
sid: this.sessionId,
client_secret: this.clientSecret,
Expand Down Expand Up @@ -279,7 +286,9 @@ export default class AddThreepid {
* with a "message" property which contains a human-readable message detailing why
* the request failed.
*/
public async haveMsisdnToken(msisdnToken: string): Promise<any[] | undefined> {
public async haveMsisdnToken(
msisdnToken: string,
): Promise<[success?: boolean, result?: IAuthData | Error | null] | undefined> {
const authClient = new IdentityAuthClient();
const supportsSeparateAddAndBind = await MatrixClientPeg.get().doesServerSupportSeparateAddAndBind();

Expand Down
2 changes: 1 addition & 1 deletion src/accessibility/context_menu/ContextMenuButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export const ContextMenuButton: React.FC<IProps> = ({
<AccessibleButton
{...props}
onClick={onClick}
onContextMenu={onContextMenu || onClick}
onContextMenu={onContextMenu ?? onClick ?? undefined}
title={label}
aria-label={label}
aria-haspopup={true}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const ContextMenuTooltipButton: React.FC<IProps> = ({
<AccessibleTooltipButton
{...props}
onClick={onClick}
onContextMenu={onContextMenu || onClick}
onContextMenu={onContextMenu ?? onClick ?? undefined}
aria-haspopup={true}
aria-expanded={isExpanded}
forceHide={isExpanded}
Expand Down
10 changes: 5 additions & 5 deletions src/actions/RoomListActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import { _t } from "../languageHandler";
import { AsyncActionPayload } from "../dispatcher/payloads";
import RoomListStore from "../stores/room-list/RoomListStore";
import { SortAlgorithm } from "../stores/room-list/algorithms/models";
import { DefaultTagID } from "../stores/room-list/models";
import { DefaultTagID, TagID } from "../stores/room-list/models";
import ErrorDialog from "../components/views/dialogs/ErrorDialog";

export default class RoomListActions {
Expand All @@ -49,10 +49,10 @@ export default class RoomListActions {
public static tagRoom(
matrixClient: MatrixClient,
room: Room,
oldTag: string,
newTag: string,
oldIndex: number | null,
newIndex: number | null,
oldTag: TagID | null,
newTag: TagID | null,
oldIndex?: number,
newIndex?: number,
): AsyncActionPayload {
let metaData: Parameters<MatrixClient["setRoomTag"]>[2] | null = null;

Expand Down
6 changes: 3 additions & 3 deletions src/audio/PlaybackQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ export class PlaybackQueue {
// Remove the now-useless clock for some space savings
this.clockStates.delete(mxEvent.getId()!);

if (wasLastPlaying) {
if (wasLastPlaying && this.currentPlaybackId) {
this.recentFullPlays.add(this.currentPlaybackId);
const orderClone = arrayFastClone(this.playbackIdOrder);
const last = orderClone.pop();
Expand Down Expand Up @@ -188,8 +188,8 @@ export class PlaybackQueue {
if (order.length === 0 || order[order.length - 1] !== this.currentPlaybackId) {
const lastInstance = this.playbacks.get(this.currentPlaybackId);
if (
lastInstance.currentState === PlaybackState.Playing ||
lastInstance.currentState === PlaybackState.Paused
lastInstance &&
[PlaybackState.Playing, PlaybackState.Paused].includes(lastInstance.currentState)
) {
order.push(this.currentPlaybackId);
}
Expand Down
3 changes: 3 additions & 0 deletions src/boundThreepids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export async function getThreepidsWithBindStatus(
try {
const authClient = new IdentityAuthClient();
const identityAccessToken = await authClient.getAccessToken({ check: false });
if (!identityAccessToken) {
throw new Error("No identity access token found");
}

// Restructure for lookup query
const query = threepids.map(({ medium, address }): [string, string] => [medium, address]);
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 @@ -29,7 +29,7 @@ export type IProps<T extends keyof JSX.IntrinsicElements> = Omit<DynamicHtmlElem
onWheel?: (event: WheelEvent) => void;
style?: React.CSSProperties;
tabIndex?: number;
wrappedRef?: (ref: HTMLDivElement) => void;
wrappedRef?: (ref: HTMLDivElement | null) => void;
children: ReactNode;
};

Expand Down
4 changes: 2 additions & 2 deletions src/components/structures/FilePanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class FilePanel extends React.Component<IProps, IState> {

const timeline = this.state.timelineSet.getLiveTimeline();
if (ev.getType() !== "m.room.message") return;
if (["m.file", "m.image", "m.video", "m.audio"].indexOf(ev.getContent().msgtype) == -1) {
if (!["m.file", "m.image", "m.video", "m.audio"].includes(ev.getContent().msgtype!)) {
return;
}

Expand Down Expand Up @@ -176,7 +176,7 @@ class FilePanel extends React.Component<IProps, IState> {
// the event index to fulfill the pagination request. Asking the server
// to paginate won't ever work since the server can't correctly filter
// out events containing URLs
if (client.isRoomEncrypted(roomId) && eventIndex !== null) {
if (room && client.isRoomEncrypted(roomId) && eventIndex !== null) {
return eventIndex.paginateTimelineWindow(room, timelineWindow, direction, limit);
} else {
return timelineWindow.paginate(direction, limit);
Expand Down
27 changes: 14 additions & 13 deletions src/components/structures/GenericDropdownMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -177,19 +177,20 @@ export function GenericDropdownMenu<T>({
</>
);
}
const contextMenu = menuDisplayed ? (
<ContextMenu
onFinished={closeMenu}
chevronFace={ChevronFace.Top}
wrapperClassName={classNames("mx_GenericDropdownMenu_wrapper", className)}
{...aboveLeftOf(button.current.getBoundingClientRect())}
>
{contextMenuOptions}
{AdditionalOptions && (
<AdditionalOptions menuDisplayed={menuDisplayed} openMenu={openMenu} closeMenu={closeMenu} />
)}
</ContextMenu>
) : null;
const contextMenu =
menuDisplayed && button.current ? (
<ContextMenu
onFinished={closeMenu}
chevronFace={ChevronFace.Top}
wrapperClassName={classNames("mx_GenericDropdownMenu_wrapper", className)}
{...aboveLeftOf(button.current.getBoundingClientRect())}
>
{contextMenuOptions}
{AdditionalOptions && (
<AdditionalOptions menuDisplayed={menuDisplayed} openMenu={openMenu} closeMenu={closeMenu} />
)}
</ContextMenu>
) : null;
return (
<>
<ContextMenuButton
Expand Down
2 changes: 1 addition & 1 deletion src/components/structures/IndicatorScrollbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default class IndicatorScrollbar<T extends keyof JSX.IntrinsicElements> e
> {
private autoHideScrollbar = createRef<AutoHideScrollbar<any>>();
private scrollElement: HTMLDivElement;
private likelyTrackpadUser: boolean = null;
private likelyTrackpadUser: boolean | null = null;
private checkAgainForTrackpad = 0; // ts in milliseconds to recheck this._likelyTrackpadUser

public constructor(props: IProps<T>) {
Expand Down
1 change: 1 addition & 0 deletions src/components/structures/LeftPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
// add appropriate sticky classes to wrapper so it has
// the necessary top/bottom padding to put the sticky header in
const listWrapper = list.parentElement; // .mx_LeftPanel_roomListWrapper
if (!listWrapper) return;
if (lastTopHeader) {
listWrapper.classList.add("mx_LeftPanel_roomListWrapper_stickyTop");
} else {
Expand Down
12 changes: 6 additions & 6 deletions src/components/structures/LegacyCallEventGrouper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,23 +85,23 @@ export default class LegacyCallEventGrouper extends EventEmitter {
);
}

private get invite(): MatrixEvent {
private get invite(): MatrixEvent | undefined {
return [...this.events].find((event) => event.getType() === EventType.CallInvite);
}

private get hangup(): MatrixEvent {
private get hangup(): MatrixEvent | undefined {
return [...this.events].find((event) => event.getType() === EventType.CallHangup);
}

private get reject(): MatrixEvent {
private get reject(): MatrixEvent | undefined {
return [...this.events].find((event) => event.getType() === EventType.CallReject);
}

private get selectAnswer(): MatrixEvent {
private get selectAnswer(): MatrixEvent | undefined {
return [...this.events].find((event) => event.getType() === EventType.CallSelectAnswer);
}

public get isVoice(): boolean {
public get isVoice(): boolean | undefined {
const invite = this.invite;
if (!invite) return;

Expand All @@ -114,7 +114,7 @@ export default class LegacyCallEventGrouper extends EventEmitter {
return this.call?.hangupReason ?? this.hangup?.getContent()?.reason ?? null;
}

public get rejectParty(): string {
public get rejectParty(): string | undefined {
return this.reject?.getSender();
}

Expand Down
24 changes: 12 additions & 12 deletions src/components/structures/LoggedInView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ class LoggedInView extends React.Component<IProps, IState> {
monitorSyncedPushRules(this._matrixClient.getAccountData("m.push_rules"), this._matrixClient);
this._matrixClient.on(ClientEvent.Sync, this.onSync);
// Call `onSync` with the current state as well
this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData());
this.onSync(this._matrixClient.getSyncState(), null, this._matrixClient.getSyncStateData() ?? undefined);
this._matrixClient.on(RoomStateEvent.Events, this.onRoomStateEvents);

this.layoutWatcherRef = SettingsStore.watchSetting("layout", null, this.onCompactLayoutChanged);
Expand Down Expand Up @@ -271,11 +271,11 @@ class LoggedInView extends React.Component<IProps, IState> {
}

private loadResizerPreferences(): void {
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size"), 10);
let lhsSize = parseInt(window.localStorage.getItem("mx_lhs_size")!, 10);
if (isNaN(lhsSize)) {
lhsSize = 350;
}
this.resizer.forHandleWithId("lp-resizer").resize(lhsSize);
this.resizer.forHandleWithId("lp-resizer")?.resize(lhsSize);
}

private onAccountData = (event: MatrixEvent): void => {
Expand All @@ -291,13 +291,13 @@ class LoggedInView extends React.Component<IProps, IState> {
});
};

private onSync = (syncState: SyncState, oldSyncState?: SyncState, data?: ISyncStateData): void => {
private onSync = (syncState: SyncState | null, oldSyncState: SyncState | null, data?: ISyncStateData): void => {
const oldErrCode = (this.state.syncErrorData?.error as MatrixError)?.errcode;
const newErrCode = (data?.error as MatrixError)?.errcode;
if (syncState === oldSyncState && oldErrCode === newErrCode) return;

this.setState({
syncErrorData: syncState === SyncState.Error ? data : null,
syncErrorData: syncState === SyncState.Error ? data : undefined,
});

if (oldSyncState === SyncState.Prepared && syncState === SyncState.Syncing) {
Expand Down Expand Up @@ -355,7 +355,7 @@ class LoggedInView extends React.Component<IProps, IState> {
const pinnedEventIds = pinStateEvent.getContent().pinned.slice(0, MAX_PINNED_NOTICES_PER_ROOM);
for (const eventId of pinnedEventIds) {
const timeline = await this._matrixClient.getEventTimeline(room.getUnfilteredTimelineSet(), eventId);
const event = timeline.getEvents().find((ev) => ev.getId() === eventId);
const event = timeline?.getEvents().find((ev) => ev.getId() === eventId);
if (event) events.push(event);
}
}
Expand Down Expand Up @@ -390,7 +390,7 @@ class LoggedInView extends React.Component<IProps, IState> {
if (inputableElement?.focus) {
inputableElement.focus();
} else {
const inThread = !!document.activeElement.closest(".mx_ThreadView");
const inThread = !!document.activeElement?.closest(".mx_ThreadView");
// refocusing during a paste event will make the paste end up in the newly focused element,
// so dispatch synchronously before paste happens
dis.dispatch(
Expand Down Expand Up @@ -533,11 +533,11 @@ class LoggedInView extends React.Component<IProps, IState> {
});
break;
case KeyBindingAction.PreviousVisitedRoomOrSpace:
PlatformPeg.get().navigateForwardBack(true);
PlatformPeg.get()?.navigateForwardBack(true);
handled = true;
break;
case KeyBindingAction.NextVisitedRoomOrSpace:
PlatformPeg.get().navigateForwardBack(false);
PlatformPeg.get()?.navigateForwardBack(false);
handled = true;
break;
}
Expand All @@ -555,7 +555,7 @@ class LoggedInView extends React.Component<IProps, IState> {
);
SettingsStore.setValue(
"showHiddenEventsInTimeline",
undefined,
null,
SettingLevel.DEVICE,
!hiddenEventVisibility,
);
Expand All @@ -567,7 +567,7 @@ class LoggedInView extends React.Component<IProps, IState> {

if (
!handled &&
PlatformPeg.get().overrideBrowserShortcuts() &&
PlatformPeg.get()?.overrideBrowserShortcuts() &&
ev.code.startsWith("Digit") &&
ev.code !== "Digit0" && // this is the shortcut for reset zoom, don't override it
isOnlyCtrlOrCmdKeyEvent(ev)
Expand Down Expand Up @@ -599,7 +599,7 @@ class LoggedInView extends React.Component<IProps, IState> {
// If the user is entering a printable character outside of an input field
// redirect it to the composer for them.
if (!isClickShortcut && isPrintable && !getInputableElement(ev.target as HTMLElement)) {
const inThread = !!document.activeElement.closest(".mx_ThreadView");
const inThread = !!document.activeElement?.closest(".mx_ThreadView");
// synchronous dispatch so we focus before key generates input
dis.dispatch(
{
Expand Down
Loading