Conform more of the codebase to strictNullChecks (#10504

* Conform more of the codebase to `strictNullChecks`

* Iterate
This commit is contained in:
Michael Telatynski 2023-04-04 11:41:46 +01:00 committed by GitHub
parent 6db0c7a1a6
commit bc60a9b594
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 60 additions and 54 deletions

View file

@ -905,7 +905,7 @@ export default class LegacyCallHandler extends EventEmitter {
const timeUntilTurnCresExpire = MatrixClientPeg.get().getTurnServersExpiry() - Date.now(); const timeUntilTurnCresExpire = MatrixClientPeg.get().getTurnServersExpiry() - Date.now();
logger.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms"); logger.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms");
const call = MatrixClientPeg.get().createCall(mappedRoomId); const call = MatrixClientPeg.get().createCall(mappedRoomId)!;
try { try {
this.addCallForRoom(roomId, call); this.addCallForRoom(roomId, call);

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { ReactElement, ReactNode, useContext, useMemo, useRef, useState } from "react"; import React, { ReactElement, ReactNode, RefObject, useContext, useMemo, useRef, useState } from "react";
import classNames from "classnames"; import classNames from "classnames";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { sleep } from "matrix-js-sdk/src/utils"; import { sleep } from "matrix-js-sdk/src/utils";
@ -140,11 +140,12 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
const cli = useContext(MatrixClientContext); const cli = useContext(MatrixClientContext);
const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors"); const msc3946ProcessDynamicPredecessor = useSettingValue<boolean>("feature_dynamic_room_predecessors");
const visibleRooms = useMemo( const visibleRooms = useMemo(
() => cli.getVisibleRooms(msc3946ProcessDynamicPredecessor).filter((r) => r.getMyMembership() === "join"), () =>
cli?.getVisibleRooms(msc3946ProcessDynamicPredecessor).filter((r) => r.getMyMembership() === "join") ?? [],
[cli, msc3946ProcessDynamicPredecessor], [cli, msc3946ProcessDynamicPredecessor],
); );
const scrollRef = useRef<AutoHideScrollbar<"div">>(); const scrollRef = useRef() as RefObject<AutoHideScrollbar<"div">>;
const [scrollState, setScrollState] = useState<IScrollState>({ const [scrollState, setScrollState] = useState<IScrollState>({
// these are estimates which update as soon as it mounts // these are estimates which update as soon as it mounts
scrollTop: 0, scrollTop: 0,
@ -212,7 +213,7 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
throw e; throw e;
}); });
setProgress((i) => i + 1); setProgress((i) => (i ?? 0) + 1);
} catch (e) { } catch (e) {
logger.error("Failed to add rooms to space", e); logger.error("Failed to add rooms to space", e);
error = e; error = e;
@ -305,13 +306,15 @@ export const AddExistingToSpace: React.FC<IAddExistingToSpaceProps> = ({
const onScroll = (): void => { const onScroll = (): void => {
const body = scrollRef.current?.containerRef.current; const body = scrollRef.current?.containerRef.current;
if (!body) return;
setScrollState({ setScrollState({
scrollTop: body.scrollTop, scrollTop: body.scrollTop,
height: body.clientHeight, height: body.clientHeight,
}); });
}; };
const wrappedRef = (body: HTMLDivElement): void => { const wrappedRef = (body: HTMLDivElement | null): void => {
if (!body) return;
setScrollState({ setScrollState({
scrollTop: body.scrollTop, scrollTop: body.scrollTop,
height: body.clientHeight, height: body.clientHeight,

View file

@ -29,7 +29,7 @@ interface IProps {
interface IState { interface IState {
isRedacting: boolean; isRedacting: boolean;
redactionErrorCode: string | number; redactionErrorCode: string | number | null;
} }
/* /*

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React, { useRef, useState, Dispatch, SetStateAction } from "react"; import React, { useRef, useState, Dispatch, SetStateAction, RefObject } from "react";
import { Room } from "matrix-js-sdk/src/matrix"; import { Room } from "matrix-js-sdk/src/matrix";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
@ -104,8 +104,8 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
} = useExportFormState(); } = useExportFormState();
const [isExporting, setExporting] = useState(false); const [isExporting, setExporting] = useState(false);
const sizeLimitRef = useRef<Field>(); const sizeLimitRef = useRef() as RefObject<Field>;
const messageCountRef = useRef<Field>(); const messageCountRef = useRef() as RefObject<Field>;
const [exportProgressText, setExportProgressText] = useState(_t("Processing…")); const [exportProgressText, setExportProgressText] = useState(_t("Processing…"));
const [displayCancel, setCancelWarning] = useState(false); const [displayCancel, setCancelWarning] = useState(false);
const [exportCancelled, setExportCancelled] = useState(false); const [exportCancelled, setExportCancelled] = useState(false);
@ -144,18 +144,18 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
const onExportClick = async (): Promise<void> => { const onExportClick = async (): Promise<void> => {
const isValidSize = const isValidSize =
!setSizeLimit || !setSizeLimit ||
(await sizeLimitRef.current.validate({ (await sizeLimitRef.current?.validate({
focused: false, focused: false,
})); }));
if (!isValidSize) { if (!isValidSize) {
sizeLimitRef.current.validate({ focused: true }); sizeLimitRef.current?.validate({ focused: true });
return; return;
} }
if (exportType === ExportType.LastNMessages) { if (exportType === ExportType.LastNMessages) {
const isValidNumberOfMessages = await messageCountRef.current.validate({ focused: false }); const isValidNumberOfMessages = await messageCountRef.current?.validate({ focused: false });
if (!isValidNumberOfMessages) { if (!isValidNumberOfMessages) {
messageCountRef.current.validate({ focused: true }); messageCountRef.current?.validate({ focused: true });
return; return;
} }
} }

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
import React from "react"; import React, { ReactNode } from "react";
import { IGeneratedSas, ISasEvent, SasEvent } from "matrix-js-sdk/src/crypto/verification/SAS"; import { IGeneratedSas, ISasEvent, SasEvent } from "matrix-js-sdk/src/crypto/verification/SAS";
import { VerificationBase, VerificationEvent } from "matrix-js-sdk/src/crypto/verification/Base"; import { VerificationBase, VerificationEvent } from "matrix-js-sdk/src/crypto/verification/Base";
import { logger } from "matrix-js-sdk/src/logger"; import { logger } from "matrix-js-sdk/src/logger";
@ -48,13 +48,13 @@ interface IState {
// eslint-disable-next-line camelcase // eslint-disable-next-line camelcase
avatar_url?: string; avatar_url?: string;
displayname?: string; displayname?: string;
}; } | null;
opponentProfileError: Error; opponentProfileError: Error | null;
sas: IGeneratedSas; sas: IGeneratedSas | null;
} }
export default class IncomingSasDialog extends React.Component<IProps, IState> { export default class IncomingSasDialog extends React.Component<IProps, IState> {
private showSasEvent: ISasEvent; private showSasEvent: ISasEvent | null;
public constructor(props: IProps) { public constructor(props: IProps) {
super(props); super(props);
@ -93,7 +93,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
}); });
} catch (e) { } catch (e) {
this.setState({ this.setState({
opponentProfileError: e, opponentProfileError: e as Error,
}); });
} }
} }
@ -133,7 +133,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
}; };
private onSasMatchesClick = (): void => { private onSasMatchesClick = (): void => {
this.showSasEvent.confirm(); this.showSasEvent?.confirm();
this.setState({ this.setState({
phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM, phase: PHASE_WAIT_FOR_PARTNER_TO_CONFIRM,
}); });
@ -143,7 +143,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
this.props.onFinished(true); this.props.onFinished(true);
}; };
private renderPhaseStart(): JSX.Element { private renderPhaseStart(): ReactNode {
const isSelf = this.props.verifier.userId === MatrixClientPeg.get().getUserId(); const isSelf = this.props.verifier.userId === MatrixClientPeg.get().getUserId();
let profile; let profile;
@ -227,7 +227,8 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
); );
} }
private renderPhaseShowSas(): JSX.Element { private renderPhaseShowSas(): ReactNode {
if (!this.showSasEvent) return null;
return ( return (
<VerificationShowSas <VerificationShowSas
sas={this.showSasEvent.sas} sas={this.showSasEvent.sas}
@ -239,7 +240,7 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
); );
} }
private renderPhaseWaitForPartnerToConfirm(): JSX.Element { private renderPhaseWaitForPartnerToConfirm(): ReactNode {
return ( return (
<div> <div>
<Spinner /> <Spinner />
@ -248,15 +249,15 @@ export default class IncomingSasDialog extends React.Component<IProps, IState> {
); );
} }
private renderPhaseVerified(): JSX.Element { private renderPhaseVerified(): ReactNode {
return <VerificationComplete onDone={this.onVerifiedDoneClick} />; return <VerificationComplete onDone={this.onVerifiedDoneClick} />;
} }
private renderPhaseCancelled(): JSX.Element { private renderPhaseCancelled(): ReactNode {
return <VerificationCancelled onDone={this.onCancelClick} />; return <VerificationCancelled onDone={this.onCancelClick} />;
} }
public render(): React.ReactNode { public render(): ReactNode {
let body; let body;
switch (this.state.phase) { switch (this.state.phase) {
case PHASE_START: case PHASE_START:

View file

@ -23,6 +23,7 @@ import DialogButtons from "../elements/DialogButtons";
import BaseDialog from "../dialogs/BaseDialog"; import BaseDialog from "../dialogs/BaseDialog";
import SpaceStore from "../../../stores/spaces/SpaceStore"; import SpaceStore from "../../../stores/spaces/SpaceStore";
import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker"; import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker";
import { filterBoolean } from "../../../utils/arrays";
interface IProps { interface IProps {
space: Room; space: Room;
@ -30,8 +31,8 @@ interface IProps {
} }
const isOnlyAdmin = (room: Room): boolean => { const isOnlyAdmin = (room: Room): boolean => {
const userId = room.client.getUserId(); const userId = room.client.getSafeUserId();
if (room.getMember(userId).powerLevelNorm !== 100) { if (room.getMember(userId)?.powerLevelNorm !== 100) {
return false; // user is not an admin return false; // user is not an admin
} }
return room.getJoinedMembers().every((member) => { return room.getJoinedMembers().every((member) => {
@ -51,9 +52,7 @@ const LeaveSpaceDialog: React.FC<IProps> = ({ space, onFinished }) => {
}, },
false, false,
); );
return Array.from(roomSet) return filterBoolean(Array.from(roomSet).map((roomId) => space.client.getRoom(roomId)));
.map((roomId) => space.client.getRoom(roomId))
.filter(Boolean);
}, [space]); }, [space]);
const [roomsToLeave, setRoomsToLeave] = useState<Room[]>([]); const [roomsToLeave, setRoomsToLeave] = useState<Room[]>([]);
const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]);

View file

@ -32,12 +32,12 @@ import InteractiveAuthDialog from "../InteractiveAuthDialog";
interface IProps { interface IProps {
accountPassword?: string; accountPassword?: string;
tokenLogin?: boolean; tokenLogin?: boolean;
onFinished?: (success?: boolean) => void; onFinished: (success?: boolean) => void;
} }
interface IState { interface IState {
error: Error | null; error: Error | null;
canUploadKeysWithPasswordOnly?: boolean; canUploadKeysWithPasswordOnly: boolean | null;
accountPassword: string; accountPassword: string;
} }
@ -73,7 +73,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
private async queryKeyUploadAuth(): Promise<void> { private async queryKeyUploadAuth(): Promise<void> {
try { try {
await MatrixClientPeg.get().uploadDeviceSigningKeys(null, {} as CrossSigningKeys); await MatrixClientPeg.get().uploadDeviceSigningKeys(undefined, {} as CrossSigningKeys);
// We should never get here: the server should always require // We should never get here: the server should always require
// UI auth to upload device signing keys. If we do, we upload // UI auth to upload device signing keys. If we do, we upload
// no keys which would be a no-op. // no keys which would be a no-op.

View file

@ -236,7 +236,7 @@ export default class MPollBody extends React.Component<IBodyProps, IState> {
* @returns userId -> UserVote * @returns userId -> UserVote
*/ */
private collectUserVotes(): Map<string, UserVote> { private collectUserVotes(): Map<string, UserVote> {
if (!this.state.voteRelations) { if (!this.state.voteRelations || !this.context) {
return new Map<string, UserVote>(); return new Map<string, UserVote>();
} }
return collectUserVotes(allVotes(this.state.voteRelations), this.context.getUserId(), this.state.selected); return collectUserVotes(allVotes(this.state.voteRelations), this.context.getUserId(), this.state.selected);

View file

@ -106,7 +106,7 @@ const PinnedMessagesCard: React.FC<IProps> = ({ room, onClose, permalinkCreator
const newlyRead = pinnedEventIds.filter((id) => !readPinnedEvents.has(id)); const newlyRead = pinnedEventIds.filter((id) => !readPinnedEvents.has(id));
if (newlyRead.length > 0) { if (newlyRead.length > 0) {
// clear out any read pinned events which no longer are pinned // clear out any read pinned events which no longer are pinned
cli.setRoomAccountData(room.roomId, ReadPinsEventId, { cli?.setRoomAccountData(room.roomId, ReadPinsEventId, {
event_ids: pinnedEventIds, event_ids: pinnedEventIds,
}); });
} }

View file

@ -77,7 +77,7 @@ export default class MemberList extends React.Component<IProps, IState> {
public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) { public constructor(props: IProps, context: React.ContextType<typeof SDKContext>) {
super(props); super(props);
this.state = this.getMembersState([], []); this.state = this.getMembersState([], []);
this.showPresence = context.memberListStore.isPresenceEnabled(); this.showPresence = context?.memberListStore.isPresenceEnabled() ?? true;
this.mounted = true; this.mounted = true;
this.listenForMembersChanges(); this.listenForMembersChanges();
} }
@ -278,7 +278,7 @@ export default class MemberList extends React.Component<IProps, IState> {
}); });
}; };
private getPending3PidInvites(): MatrixEvent[] | undefined { private getPending3PidInvites(): MatrixEvent[] {
// include 3pid invites (m.room.third_party_invite) state events. // include 3pid invites (m.room.third_party_invite) state events.
// The HS may have already converted these into m.room.member invites so // The HS may have already converted these into m.room.member invites so
// we shouldn't add them if the 3pid invite state key (token) is in the // we shouldn't add them if the 3pid invite state key (token) is in the
@ -291,11 +291,13 @@ export default class MemberList extends React.Component<IProps, IState> {
// discard all invites which have a m.room.member event since we've // discard all invites which have a m.room.member event since we've
// already added them. // already added them.
const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey()); const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey()!);
if (memberEvent) return false; if (memberEvent) return false;
return true; return true;
}); });
} }
return [];
} }
private makeMemberTiles(members: Array<RoomMember | MatrixEvent>): JSX.Element[] { private makeMemberTiles(members: Array<RoomMember | MatrixEvent>): JSX.Element[] {

View file

@ -57,7 +57,7 @@ export interface IRightPanelCard {
} }
export interface IRightPanelCardStored { export interface IRightPanelCardStored {
phase: RightPanelPhases; phase: RightPanelPhases | null;
state?: IRightPanelCardStateStored; state?: IRightPanelCardStateStored;
} }

View file

@ -28,7 +28,7 @@ export const useBeacon = (beaconInfoEvent: MatrixEvent): Beacon | undefined => {
const roomId = beaconInfoEvent.getRoomId(); const roomId = beaconInfoEvent.getRoomId();
const beaconIdentifier = getBeaconInfoIdentifier(beaconInfoEvent); const beaconIdentifier = getBeaconInfoIdentifier(beaconInfoEvent);
const room = matrixClient.getRoom(roomId); const room = matrixClient?.getRoom(roomId);
const beaconInstance = room?.currentState.beacons.get(beaconIdentifier); const beaconInstance = room?.currentState.beacons.get(beaconIdentifier);
// TODO could this be less stupid? // TODO could this be less stupid?

View file

@ -475,8 +475,8 @@ function isHostnameIpAddress(hostname: string): boolean {
return isIp(hostname); return isIp(hostname);
} }
export const calculateRoomVia = (room: Room): string[] | undefined => { export const calculateRoomVia = (room: Room): string[] => {
const permalinkCreator = new RoomPermalinkCreator(room); const permalinkCreator = new RoomPermalinkCreator(room);
permalinkCreator.load(); permalinkCreator.load();
return permalinkCreator.serverCandidates; return permalinkCreator.serverCandidates ?? [];
}; };

View file

@ -26,7 +26,7 @@ export const useHasRoomLiveVoiceBroadcast = (room: Room): boolean => {
const [hasLiveVoiceBroadcast, setHasLiveVoiceBroadcast] = useState(false); const [hasLiveVoiceBroadcast, setHasLiveVoiceBroadcast] = useState(false);
const update = useMemo(() => { const update = useMemo(() => {
return sdkContext.client return sdkContext?.client
? () => { ? () => {
hasRoomLiveVoiceBroadcast(sdkContext.client!, room).then( hasRoomLiveVoiceBroadcast(sdkContext.client!, room).then(
({ hasBroadcast }) => { ({ hasBroadcast }) => {

View file

@ -365,7 +365,7 @@ describe("LegacyCallHandler", () => {
fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({ fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({
id: NATIVE_BOB, id: NATIVE_BOB,
}); });
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall); fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall!);
// Now set the config option // Now set the config option
SdkConfig.add({ SdkConfig.add({
@ -378,7 +378,7 @@ describe("LegacyCallHandler", () => {
fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({ fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({
id: NATIVE_CHARLIE, id: NATIVE_CHARLIE,
}); });
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall); fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall!);
await roomChangePromise; await roomChangePromise;
callHandler.removeAllListeners(); callHandler.removeAllListeners();
@ -624,7 +624,7 @@ describe("LegacyCallHandler without third party protocols", () => {
// call added to call map // call added to call map
expect(callHandler.getCallForRoom(roomId)).toEqual(call); expect(callHandler.getCallForRoom(roomId)).toEqual(call);
call.emit(CallEvent.State, CallState.Ringing, CallState.Connected, fakeCall); call.emit(CallEvent.State, CallState.Ringing, CallState.Connected, fakeCall!);
// ringer audio element started // ringer audio element started
expect(mockAudioElement.play).toHaveBeenCalled(); expect(mockAudioElement.play).toHaveBeenCalled();
@ -641,7 +641,7 @@ describe("LegacyCallHandler without third party protocols", () => {
// call added to call map // call added to call map
expect(callHandler.getCallForRoom(roomId)).toEqual(call); expect(callHandler.getCallForRoom(roomId)).toEqual(call);
call.emit(CallEvent.State, CallState.Ringing, CallState.Connected, fakeCall); call.emit(CallEvent.State, CallState.Ringing, CallState.Connected, fakeCall!);
// ringer audio element started // ringer audio element started
expect(mockAudioElement.play).not.toHaveBeenCalled(); expect(mockAudioElement.play).not.toHaveBeenCalled();

View file

@ -42,7 +42,7 @@ describe("NotificatinSettingsTab", () => {
const room = mkStubRoom(roomId, "test room", cli); const room = mkStubRoom(roomId, "test room", cli);
roomProps = EchoChamber.forRoom(room); roomProps = EchoChamber.forRoom(room);
NotificationSettingsTab.contextType = React.createContext(cli); NotificationSettingsTab.contextType = React.createContext<MatrixClient | undefined>(cli);
}); });
it("should prevent »Settings« link click from bubbling up to radio buttons", async () => { it("should prevent »Settings« link click from bubbling up to radio buttons", async () => {

View file

@ -185,7 +185,7 @@ describe("StopGapWidgetDriver", () => {
const aliceMobile = new DeviceInfo("aliceMobile"); const aliceMobile = new DeviceInfo("aliceMobile");
const bobDesktop = new DeviceInfo("bobDesktop"); const bobDesktop = new DeviceInfo("bobDesktop");
mocked(client.crypto.deviceList).downloadKeys.mockResolvedValue( mocked(client.crypto!.deviceList).downloadKeys.mockResolvedValue(
new Map([ new Map([
[ [
"@alice:example.org", "@alice:example.org",

View file

@ -163,8 +163,9 @@ describe("DMRoomMap", () => {
beforeEach(() => { beforeEach(() => {
client.getAccountData.mockReturnValue(mkMDirectEvent(mDirectContent)); client.getAccountData.mockReturnValue(mkMDirectEvent(mDirectContent));
client.getRoom.mockImplementation((roomId: string) => client.getRoom.mockImplementation(
[bigRoom, smallRoom, dmWithCharlie, dmWithBob].find((room) => room.roomId === roomId), (roomId: string) =>
[bigRoom, smallRoom, dmWithCharlie, dmWithBob].find((room) => room.roomId === roomId) ?? null,
); );
}); });
@ -183,7 +184,7 @@ describe("DMRoomMap", () => {
}); });
it("excludes rooms that are not found by matrixClient", () => { it("excludes rooms that are not found by matrixClient", () => {
client.getRoom.mockReset().mockReturnValue(undefined); client.getRoom.mockReset().mockReturnValue(null);
const dmRoomMap = new DMRoomMap(client); const dmRoomMap = new DMRoomMap(client);
dmRoomMap.start(); dmRoomMap.start();
expect(dmRoomMap.getUniqueRoomsWithIndividuals()).toEqual({}); expect(dmRoomMap.getUniqueRoomsWithIndividuals()).toEqual({});