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();
logger.log("Current turn creds expire in " + timeUntilTurnCresExpire + " ms");
const call = MatrixClientPeg.get().createCall(mappedRoomId);
const call = MatrixClientPeg.get().createCall(mappedRoomId)!;
try {
this.addCallForRoom(roomId, call);

View file

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

View file

@ -29,7 +29,7 @@ interface IProps {
interface IState {
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.
*/
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 { logger } from "matrix-js-sdk/src/logger";
@ -104,8 +104,8 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
} = useExportFormState();
const [isExporting, setExporting] = useState(false);
const sizeLimitRef = useRef<Field>();
const messageCountRef = useRef<Field>();
const sizeLimitRef = useRef() as RefObject<Field>;
const messageCountRef = useRef() as RefObject<Field>;
const [exportProgressText, setExportProgressText] = useState(_t("Processing…"));
const [displayCancel, setCancelWarning] = useState(false);
const [exportCancelled, setExportCancelled] = useState(false);
@ -144,18 +144,18 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
const onExportClick = async (): Promise<void> => {
const isValidSize =
!setSizeLimit ||
(await sizeLimitRef.current.validate({
(await sizeLimitRef.current?.validate({
focused: false,
}));
if (!isValidSize) {
sizeLimitRef.current.validate({ focused: true });
sizeLimitRef.current?.validate({ focused: true });
return;
}
if (exportType === ExportType.LastNMessages) {
const isValidNumberOfMessages = await messageCountRef.current.validate({ focused: false });
const isValidNumberOfMessages = await messageCountRef.current?.validate({ focused: false });
if (!isValidNumberOfMessages) {
messageCountRef.current.validate({ focused: true });
messageCountRef.current?.validate({ focused: true });
return;
}
}

View file

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

View file

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

View file

@ -32,12 +32,12 @@ import InteractiveAuthDialog from "../InteractiveAuthDialog";
interface IProps {
accountPassword?: string;
tokenLogin?: boolean;
onFinished?: (success?: boolean) => void;
onFinished: (success?: boolean) => void;
}
interface IState {
error: Error | null;
canUploadKeysWithPasswordOnly?: boolean;
canUploadKeysWithPasswordOnly: boolean | null;
accountPassword: string;
}
@ -73,7 +73,7 @@ export default class CreateCrossSigningDialog extends React.PureComponent<IProps
private async queryKeyUploadAuth(): Promise<void> {
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
// UI auth to upload device signing keys. If we do, we upload
// 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
*/
private collectUserVotes(): Map<string, UserVote> {
if (!this.state.voteRelations) {
if (!this.state.voteRelations || !this.context) {
return new Map<string, UserVote>();
}
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));
if (newlyRead.length > 0) {
// clear out any read pinned events which no longer are pinned
cli.setRoomAccountData(room.roomId, ReadPinsEventId, {
cli?.setRoomAccountData(room.roomId, ReadPinsEventId, {
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>) {
super(props);
this.state = this.getMembersState([], []);
this.showPresence = context.memberListStore.isPresenceEnabled();
this.showPresence = context?.memberListStore.isPresenceEnabled() ?? true;
this.mounted = true;
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.
// 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
@ -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
// already added them.
const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey());
const memberEvent = room.currentState.getInviteForThreePidToken(e.getStateKey()!);
if (memberEvent) return false;
return true;
});
}
return [];
}
private makeMemberTiles(members: Array<RoomMember | MatrixEvent>): JSX.Element[] {

View file

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

View file

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

View file

@ -475,8 +475,8 @@ function isHostnameIpAddress(hostname: string): boolean {
return isIp(hostname);
}
export const calculateRoomVia = (room: Room): string[] | undefined => {
export const calculateRoomVia = (room: Room): string[] => {
const permalinkCreator = new RoomPermalinkCreator(room);
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 update = useMemo(() => {
return sdkContext.client
return sdkContext?.client
? () => {
hasRoomLiveVoiceBroadcast(sdkContext.client!, room).then(
({ hasBroadcast }) => {

View file

@ -365,7 +365,7 @@ describe("LegacyCallHandler", () => {
fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({
id: NATIVE_BOB,
});
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall);
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall!);
// Now set the config option
SdkConfig.add({
@ -378,7 +378,7 @@ describe("LegacyCallHandler", () => {
fakeCall!.getRemoteAssertedIdentity = jest.fn().mockReturnValue({
id: NATIVE_CHARLIE,
});
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall);
fakeCall!.emit(CallEvent.AssertedIdentityChanged, fakeCall!);
await roomChangePromise;
callHandler.removeAllListeners();
@ -624,7 +624,7 @@ describe("LegacyCallHandler without third party protocols", () => {
// call added to call map
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
expect(mockAudioElement.play).toHaveBeenCalled();
@ -641,7 +641,7 @@ describe("LegacyCallHandler without third party protocols", () => {
// call added to call map
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
expect(mockAudioElement.play).not.toHaveBeenCalled();

View file

@ -42,7 +42,7 @@ describe("NotificatinSettingsTab", () => {
const room = mkStubRoom(roomId, "test room", cli);
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 () => {

View file

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

View file

@ -163,8 +163,9 @@ describe("DMRoomMap", () => {
beforeEach(() => {
client.getAccountData.mockReturnValue(mkMDirectEvent(mDirectContent));
client.getRoom.mockImplementation((roomId: string) =>
[bigRoom, smallRoom, dmWithCharlie, dmWithBob].find((room) => room.roomId === roomId),
client.getRoom.mockImplementation(
(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", () => {
client.getRoom.mockReset().mockReturnValue(undefined);
client.getRoom.mockReset().mockReturnValue(null);
const dmRoomMap = new DMRoomMap(client);
dmRoomMap.start();
expect(dmRoomMap.getUniqueRoomsWithIndividuals()).toEqual({});