Conform more of the codebase with strictNullChecks (#10703)

This commit is contained in:
Michael Telatynski 2023-04-25 09:28:48 +01:00 committed by GitHub
parent db40479910
commit 619a9e8542
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 108 additions and 77 deletions

View file

@ -69,7 +69,7 @@ export default class CountryDropdown extends React.Component<IProps, IState> {
const locale = new Intl.Locale(navigator.language ?? navigator.languages[0]);
const code = locale.region ?? locale.language ?? locale.baseName;
const displayNames = new Intl.DisplayNames(["en"], { type: "region" });
const displayName = displayNames.of(code).toUpperCase();
const displayName = displayNames.of(code)?.toUpperCase();
defaultCountry = COUNTRIES.find(
(c) => c.iso2 === code.toUpperCase() || c.name.toUpperCase() === displayName,
);

View file

@ -49,7 +49,7 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
super(props);
const config = SdkConfig.get();
this.defaultServer = config["validated_server_config"];
this.defaultServer = config["validated_server_config"]!;
const { serverConfig } = this.props;
let otherHomeserver = "";
@ -152,11 +152,11 @@ export default class ServerPickerDialog extends React.PureComponent<IProps, ISta
private onSubmit = async (ev: SyntheticEvent): Promise<void> => {
ev.preventDefault();
const valid = await this.fieldRef.current.validate({ allowEmpty: false });
const valid = await this.fieldRef.current?.validate({ allowEmpty: false });
if (!valid && !this.state.defaultChosen) {
this.fieldRef.current.focus();
this.fieldRef.current.validate({ allowEmpty: false, focused: true });
this.fieldRef.current?.focus();
this.fieldRef.current?.validate({ allowEmpty: false, focused: true });
return;
}

View file

@ -1089,7 +1089,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
ev.stopPropagation();
ev.preventDefault();
if (rovingContext.state.refs.length > 0) {
if (rovingContext.state.activeRef && rovingContext.state.refs.length > 0) {
let refs = rovingContext.state.refs;
if (!query && !filter !== null) {
// If the current selection is not in the recently viewed row then only include the
@ -1112,6 +1112,7 @@ const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = n
if (
!query &&
!filter !== null &&
rovingContext.state.activeRef &&
rovingContext.state.refs.length > 0 &&
refIsForRecentlyViewed(rovingContext.state.activeRef)
) {

View file

@ -25,7 +25,7 @@ import AccessibleTooltipButton from "./AccessibleTooltipButton";
interface IProps {
children?: React.ReactNode;
getTextToCopy: () => string;
getTextToCopy: () => string | null;
border?: boolean;
className?: string;
}
@ -35,7 +35,8 @@ const CopyableText: React.FC<IProps> = ({ children, getTextToCopy, border = true
const onCopyClickInternal = async (e: ButtonEvent): Promise<void> => {
e.preventDefault();
const successful = await copyPlaintext(getTextToCopy());
const text = getTextToCopy();
const successful = !!text && (await copyPlaintext(text));
setTooltip(successful ? _t("Copied!") : _t("Failed to copy"));
};

View file

@ -162,9 +162,9 @@ class EmojiPicker extends React.Component<IProps, IState> {
};
private keyboardNavigation(ev: React.KeyboardEvent, state: RovingState, dispatch: Dispatch<RovingAction>): void {
const node = state.activeRef.current;
const parent = node.parentElement;
if (!parent) return;
const node = state.activeRef?.current;
const parent = node?.parentElement;
if (!parent || !state.activeRef) return;
const rowIndex = Array.from(parent.children).indexOf(node);
const refIndex = state.refs.indexOf(state.activeRef);
@ -173,12 +173,12 @@ class EmojiPicker extends React.Component<IProps, IState> {
switch (ev.key) {
case Key.ARROW_LEFT:
focusRef = state.refs[refIndex - 1];
newParent = focusRef?.current?.parentElement;
newParent = focusRef?.current?.parentElement ?? undefined;
break;
case Key.ARROW_RIGHT:
focusRef = state.refs[refIndex + 1];
newParent = focusRef?.current?.parentElement;
newParent = focusRef?.current?.parentElement ?? undefined;
break;
case Key.ARROW_UP:
@ -188,7 +188,7 @@ class EmojiPicker extends React.Component<IProps, IState> {
ev.key === Key.ARROW_UP
? state.refs[refIndex - rowIndex - 1]
: state.refs[refIndex - rowIndex + EMOJIS_PER_ROW];
newParent = ref?.current?.parentElement;
newParent = ref?.current?.parentElement ?? undefined;
const newTarget = newParent?.children[clamp(rowIndex, 0, newParent.children.length - 1)];
focusRef = state.refs.find((r) => r.current === newTarget);
break;

View file

@ -386,8 +386,8 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
// in case we're currently editing a pending event
const sel = document.getSelection()!;
let caret: DocumentOffset | undefined;
if (sel.focusNode) {
caret = getCaretOffsetAndText(this.editorRef.current?.editorRef.current, sel).caret;
if (sel.focusNode && this.editorRef.current?.editorRef.current) {
caret = getCaretOffsetAndText(this.editorRef.current.editorRef.current, sel).caret;
}
const parts = this.model.serializeParts();
// if caret is undefined because for some reason there isn't a valid selection,
@ -458,12 +458,15 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
};
public render(): React.ReactNode {
const room = this.getRoom();
if (!room) return null;
return (
<div className={classNames("mx_EditMessageComposer", this.props.className)} onKeyDown={this.onKeyDown}>
<BasicMessageComposer
ref={this.editorRef}
model={this.model}
room={this.getRoom()}
room={room}
threadId={this.props.editState?.getEvent()?.getThread()?.id}
initialCaret={this.props.editState.getCaret() ?? undefined}
label={_t("Edit message")}

View file

@ -16,7 +16,7 @@ limitations under the License.
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
import { Room } from "matrix-js-sdk/src/models/room";
import React, { ComponentType, createRef, ReactComponentElement, RefObject, SyntheticEvent } from "react";
import React, { ComponentType, createRef, ReactComponentElement, SyntheticEvent } from "react";
import { IState as IRovingTabIndexState, RovingTabIndexProvider } from "../../../accessibility/RovingTabIndex";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
@ -106,8 +106,8 @@ type TagAestheticsMap = Partial<{
[tagId in TagID]: ITagAesthetics;
}>;
const auxButtonContextMenuPosition = (handle: RefObject<HTMLDivElement>): MenuProps => {
const rect = handle.current.getBoundingClientRect();
const auxButtonContextMenuPosition = (handle: HTMLDivElement): MenuProps => {
const rect = handle.getBoundingClientRect();
return {
chevronFace: ChevronFace.None,
left: rect.left - 7,
@ -126,11 +126,11 @@ const DmAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex, dispatcher = default
if (activeSpace && (showCreateRooms || showInviteUsers)) {
let contextMenu: JSX.Element | undefined;
if (menuDisplayed) {
if (menuDisplayed && handle.current) {
const canInvite = shouldShowSpaceInvite(activeSpace);
contextMenu = (
<IconizedContextMenu {...auxButtonContextMenuPosition(handle)} onFinished={closeMenu} compact>
<IconizedContextMenu {...auxButtonContextMenuPosition(handle.current)} onFinished={closeMenu} compact>
<IconizedContextMenuOptionList first>
{showCreateRooms && (
<IconizedContextMenuOption
@ -357,9 +357,9 @@ const UntaggedAuxButton: React.FC<IAuxButtonProps> = ({ tabIndex }) => {
}
let contextMenu: JSX.Element | null = null;
if (menuDisplayed) {
if (menuDisplayed && handle.current) {
contextMenu = (
<IconizedContextMenu {...auxButtonContextMenuPosition(handle)} onFinished={closeMenu} compact>
<IconizedContextMenu {...auxButtonContextMenuPosition(handle.current)} onFinished={closeMenu} compact>
{contextMenuContent}
</IconizedContextMenu>
);
@ -491,6 +491,7 @@ export default class RoomList extends React.PureComponent<IProps, IState> {
if (payload.action === Action.ViewRoomDelta) {
const viewRoomDeltaPayload = payload as ViewRoomDeltaPayload;
const currentRoomId = SdkContextClass.instance.roomViewStore.getRoomId();
if (!currentRoomId) return;
const room = this.getRoomDelta(currentRoomId, viewRoomDeltaPayload.delta, viewRoomDeltaPayload.unread);
if (room) {
defaultDispatcher.dispatch<ViewRoomPayload>({

View file

@ -207,7 +207,8 @@ export class RoomTile extends React.PureComponent<ClassProps, State> {
return;
}
const messagePreview = await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag);
const messagePreview =
(await MessagePreviewStore.instance.getPreviewForRoom(this.props.room, this.props.tag)) ?? undefined;
this.setState({ messagePreview });
}

View file

@ -38,7 +38,7 @@ export function usePlainTextListeners(
onChange?: (content: string) => void,
onSend?: () => void,
): {
ref: RefObject<HTMLDivElement | null>;
ref: RefObject<HTMLDivElement>;
content?: string;
onInput(event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>): void;
onPaste(event: SyntheticEvent<HTMLDivElement, InputEvent | ClipboardEvent>): void;

View file

@ -295,7 +295,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
const verify = (sub: string): JSX.Element => (
<span
className={
sig.device && sig.deviceTrust.isVerified()
sig.device && sig.deviceTrust?.isVerified()
? "mx_SecureBackupPanel_deviceVerified"
: "mx_SecureBackupPanel_deviceNotVerified"
}
@ -347,7 +347,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
{},
{ validity },
);
} else if (sig.valid && sig.deviceTrust.isVerified()) {
} else if (sig.valid && sig.deviceTrust?.isVerified()) {
sigStatus = _t(
"Backup has a <validity>valid</validity> signature from " +
"<verify>verified</verify> session <device></device>",
@ -361,7 +361,7 @@ export default class SecureBackupPanel extends React.PureComponent<{}, IState> {
{},
{ validity, verify, device },
);
} else if (!sig.valid && sig.deviceTrust.isVerified()) {
} else if (!sig.valid && sig.deviceTrust?.isVerified()) {
sigStatus = _t(
"Backup has an <validity>invalid</validity> signature from " +
"<verify>verified</verify> session <device></device>",

View file

@ -67,7 +67,7 @@ export default class LabsUserSettingsTab extends React.Component<{}> {
const groups = new EnhancedMap<LabGroup, JSX.Element[]>();
this.labs.forEach((f) => {
groups
.getOrCreate(SettingsStore.getLabGroup(f), [])
.getOrCreate(SettingsStore.getLabGroup(f)!, [])
.push(<SettingsFlag level={SettingLevel.DEVICE} name={f} key={f} />);
});

View file

@ -68,14 +68,14 @@ const QuickSettingsButton: React.FC<{
{_t("All settings")}
</AccessibleButton>
{SettingsStore.getValue("developerMode") && (
{SettingsStore.getValue("developerMode") && SdkContextClass.instance.roomViewStore.getRoomId() && (
<AccessibleButton
onClick={() => {
closeMenu();
Modal.createDialog(
DevtoolsDialog,
{
roomId: SdkContextClass.instance.roomViewStore.getRoomId(),
roomId: SdkContextClass.instance.roomViewStore.getRoomId()!,
},
"mx_DevtoolsDialog_wrapper",
);

View file

@ -122,7 +122,7 @@ export const SpaceButton = forwardRef<HTMLElement, IButtonProps>(
}
let contextMenu: JSX.Element | undefined;
if (menuDisplayed && handle.current && ContextMenuComponent) {
if (space && menuDisplayed && handle.current && ContextMenuComponent) {
contextMenu = (
<ContextMenuComponent
{...toRightOf(handle.current.getBoundingClientRect(), 0)}

View file

@ -74,10 +74,12 @@ export default class VerificationRequestToast extends React.PureComponent<IProps
if (request.isSelfVerification) {
const cli = MatrixClientPeg.get();
const device = await cli.getDevice(request.channel.deviceId);
const ip = device.last_seen_ip;
const device = request.channel.deviceId ? await cli.getDevice(request.channel.deviceId) : null;
const ip = device?.last_seen_ip;
this.setState({
device: cli.getStoredDevice(cli.getUserId()!, request.channel.deviceId) ?? undefined,
device:
(request.channel.deviceId && cli.getStoredDevice(cli.getSafeUserId(), request.channel.deviceId)) ||
undefined,
ip,
});
}