Conform more of the codebase to strictNullChecks (#10602)

* Conform more of the codebase to `strictNullChecks`

* Conform more of the codebase to `strictNullChecks`

* Fix types
This commit is contained in:
Michael Telatynski 2023-04-17 08:31:58 +01:00 committed by GitHub
parent 93858813a3
commit daad630827
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 79 additions and 49 deletions

View file

@ -231,7 +231,7 @@ class LoggedInView extends React.Component<IProps, IState> {
};
private createResizer(): Resizer {
let panelSize: number;
let panelSize: number | null;
let panelCollapsed: boolean;
const collapseConfig: ICollapseConfig = {
// TODO decrease this once Spaces launches as it'll no longer need to include the 56px Community Panel

View file

@ -110,6 +110,7 @@ export default class RoomAvatar extends React.Component<IProps, IState> {
private onRoomAvatarClick = (): void => {
const avatarUrl = Avatar.avatarUrlForRoom(this.props.room ?? null, undefined, undefined, undefined);
if (!avatarUrl) return;
const params = {
src: avatarUrl,
name: this.props.room?.name,

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { RefObject, useRef, useState } from "react";
import React, { 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";
@ -41,9 +41,9 @@ const CreateSubspaceDialog: React.FC<IProps> = ({ space, onAddExistingSpaceClick
const [busy, setBusy] = useState<boolean>(false);
const [name, setName] = useState("");
const spaceNameField = useRef() as RefObject<Field>;
const spaceNameField = useRef<Field>(null);
const [alias, setAlias] = useState("");
const spaceAliasField = useRef() as RefObject<RoomAliasField>;
const spaceAliasField = useRef<RoomAliasField>(null);
const [avatar, setAvatar] = useState<File | undefined>();
const [topic, setTopic] = useState<string>("");

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, RefObject } from "react";
import React, { useRef, useState, Dispatch, SetStateAction } 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() as RefObject<Field>;
const messageCountRef = useRef() as RefObject<Field>;
const sizeLimitRef = useRef<Field>(null);
const messageCountRef = useRef<Field>(null);
const [exportProgressText, setExportProgressText] = useState(_t("Processing…"));
const [displayCancel, setCancelWarning] = useState(false);
const [exportCancelled, setExportCancelled] = useState(false);

View file

@ -15,7 +15,7 @@ limitations under the License.
*/
import * as React from "react";
import { RefObject, SyntheticEvent, useRef, useState } from "react";
import { SyntheticEvent, useRef, useState } from "react";
import { _t, _td } from "../../../languageHandler";
import Field from "../elements/Field";
@ -30,7 +30,7 @@ interface IProps {
const RegistrationEmailPromptDialog: React.FC<IProps> = ({ onFinished }) => {
const [email, setEmail] = useState("");
const fieldRef = useRef() as RefObject<Field>;
const fieldRef = useRef<Field>(null);
const onSubmit = async (e: SyntheticEvent): Promise<void> => {
e.preventDefault();

View file

@ -255,7 +255,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
});
} else {
// Report to homeserver admin through the dedicated Matrix API.
await client.reportEvent(ev.getRoomId(), ev.getId(), -100, this.state.reason.trim());
await client.reportEvent(ev.getRoomId()!, ev.getId()!, -100, this.state.reason.trim());
}
// if the user should also be ignored, do that
@ -340,7 +340,7 @@ export default class ReportEventDialog extends React.Component<IProps, IState> {
);
break;
case NonStandardValue.Admin:
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId())) {
if (client.isRoomEncrypted(this.props.mxEvent.getRoomId()!)) {
subtitle = _t(
"This room is dedicated to illegal or toxic content " +
"or the moderators fail to moderate illegal or toxic content.\n" +

View file

@ -288,8 +288,8 @@ interface IDirectoryOpts {
}
const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = null, onFinished }) => {
const inputRef = useRef() as RefObject<HTMLInputElement>;
const scrollContainerRef = useRef() as RefObject<HTMLDivElement>;
const inputRef = useRef<HTMLInputElement>(null);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const cli = MatrixClientPeg.get();
const rovingContext = useContext(RovingTabIndexContext);
const [query, _setQuery] = useState(initialText);

View file

@ -16,7 +16,7 @@ limitations under the License.
import classNames from "classnames";
import { EventType } from "matrix-js-sdk/src/@types/event";
import React, { useContext, useRef, useState, MouseEvent, ReactNode, RefObject } from "react";
import React, { useContext, useRef, useState, MouseEvent, ReactNode } from "react";
import MatrixClientContext from "../../../contexts/MatrixClientContext";
import RoomContext from "../../../contexts/RoomContext";
@ -59,7 +59,7 @@ const MiniAvatarUploader: React.FC<IProps> = ({
setShow(false);
}, 13000); // hide after being shown for 10 seconds
const uploadRef = useRef() as RefObject<HTMLInputElement>;
const uploadRef = useRef<HTMLInputElement>(null);
const label = hasAvatar || busy ? hasAvatarLabel : noAvatarLabel;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { RefObject, useCallback, useContext, useRef } from "react";
import React, { useCallback, useContext, useRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import classNames from "classnames";
import { EventType } from "matrix-js-sdk/src/@types/event";
@ -38,7 +38,7 @@ interface IProps extends React.HTMLProps<HTMLDivElement> {
export default function RoomTopic({ room, ...props }: IProps): JSX.Element {
const client = useContext(MatrixClientContext);
const ref = useRef() as RefObject<HTMLDivElement>;
const ref = useRef<HTMLDivElement>(null);
const topic = useTopic(room);
const body = topicToHtml(topic?.text, topic?.html, ref);

View file

@ -1504,9 +1504,10 @@ export const UserInfoHeader: React.FC<{
const avatarUrl = (member as RoomMember).getMxcAvatarUrl
? (member as RoomMember).getMxcAvatarUrl()
: (member as User).avatarUrl;
if (!avatarUrl) return;
const httpUrl = mediaFromMxc(avatarUrl).srcHttp;
if (!httpUrl) return;
const params = {
src: httpUrl,
name: (member as RoomMember).name || (member as User).displayName,

View file

@ -100,14 +100,14 @@ export default class AuxPanel extends React.Component<IProps, IState> {
if (this.props.room && SettingsStore.getValue("feature_state_counters")) {
const stateEvs = this.props.room.currentState.getStateEvents("re.jki.counter");
stateEvs.sort((a, b) => lexicographicCompare(a.getStateKey(), b.getStateKey()));
stateEvs.sort((a, b) => lexicographicCompare(a.getStateKey()!, b.getStateKey()!));
for (const ev of stateEvs) {
const title = ev.getContent().title;
const value = ev.getContent().value;
const link = ev.getContent().link;
const severity = ev.getContent().severity || "normal";
const stateKey = ev.getStateKey();
const stateKey = ev.getStateKey()!;
// We want a non-empty title but can accept falsy values (e.g.
// zero)

View file

@ -765,7 +765,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
public render(): React.ReactNode {
let autoComplete: JSX.Element | undefined;
if (this.state.autoComplete) {
if (this.state.autoComplete && this.state.query) {
const query = this.state.query;
const queryLen = query.length;
autoComplete = (
@ -800,8 +800,8 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
const { completionIndex } = this.state;
const hasAutocomplete = Boolean(this.state.autoComplete);
let activeDescendant: string | undefined;
if (hasAutocomplete && completionIndex >= 0) {
activeDescendant = generateCompletionDomId(completionIndex);
if (hasAutocomplete && completionIndex! >= 0) {
activeDescendant = generateCompletionDomId(completionIndex!);
}
return (

View file

@ -229,11 +229,11 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
}
private get editorRoomKey(): string {
return editorRoomKey(this.props.editState.getEvent().getRoomId(), this.context.timelineRenderingType);
return editorRoomKey(this.props.editState.getEvent().getRoomId()!, this.context.timelineRenderingType);
}
private get editorStateKey(): string {
return editorStateKey(this.props.editState.getEvent().getId());
return editorStateKey(this.props.editState.getEvent().getId()!);
}
private get events(): MatrixEvent[] {
@ -275,7 +275,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
private saveStoredEditorState = (): void => {
const item = SendHistoryManager.createItem(this.model);
this.clearPreviousEdit();
localStorage.setItem(this.editorRoomKey, this.props.editState.getEvent().getId());
localStorage.setItem(this.editorRoomKey, this.props.editState.getEvent().getId()!);
localStorage.setItem(this.editorStateKey, JSON.stringify(item));
};
@ -329,7 +329,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
// If content is modified then send an updated event into the room
if (this.isContentModified(newContent)) {
const roomId = editedEvent.getRoomId();
const roomId = editedEvent.getRoomId()!;
if (!containsEmote(this.model) && isSlashCommand(this.model)) {
const [cmd, args, commandText] = getSlashCommand(this.model);
if (cmd) {

View file

@ -43,11 +43,13 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
if (ev.button != 0 || ev.metaKey) return;
ev.preventDefault();
let src = p["og:image"];
let src: string | null | undefined = p["og:image"];
if (src?.startsWith("mxc://")) {
src = mediaFromMxc(src).srcHttp;
}
if (!src) return;
const params: Omit<ComponentProps<typeof ImageView>, "onFinished"> = {
src: src,
width: p["og:image:width"],

View file

@ -17,7 +17,7 @@ limitations under the License.
import classNames from "classnames";
import { IEventRelation } from "matrix-js-sdk/src/models/event";
import { M_POLL_START } from "matrix-js-sdk/src/@types/polls";
import React, { createContext, MouseEventHandler, ReactElement, ReactNode, RefObject, useContext, useRef } from "react";
import React, { createContext, MouseEventHandler, ReactElement, ReactNode, useContext, useRef } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClient } from "matrix-js-sdk/src/client";
import { THREAD_RELATION_TYPE } from "matrix-js-sdk/src/models/thread";
@ -180,7 +180,7 @@ interface IUploadButtonProps {
const UploadButtonContextProvider: React.FC<IUploadButtonProps> = ({ roomId, relation, children }) => {
const cli = useContext(MatrixClientContext);
const roomContext = useContext(RoomContext);
const uploadInput = useRef() as RefObject<HTMLInputElement>;
const uploadInput = useRef<HTMLInputElement>(null);
const onUploadClick = (): void => {
if (cli?.isGuest()) {

View file

@ -293,7 +293,7 @@ interface ISectionHeaderProps {
}
function SectionHeader({ className, children }: PropsWithChildren<ISectionHeaderProps>): JSX.Element {
const ref = useRef<HTMLHeadingElement>();
const ref = useRef<HTMLHeadingElement>(null);
const [onFocus] = useRovingTabIndex(ref);
return (

View file

@ -124,7 +124,7 @@ export default class ReadReceiptMarker extends React.PureComponent<IProps, IStat
private buildReadReceiptInfo(target: IReadReceiptInfo = {}): IReadReceiptInfo {
const element = this.avatar.current;
// this is the mx_ReadReceiptsGroup_container
const horizontalContainer = element.offsetParent;
const horizontalContainer = element?.offsetParent;
if (!horizontalContainer || !(horizontalContainer instanceof HTMLElement)) {
// this seems to happen sometimes for reasons I don't understand
// the docs for `offsetParent` say it may be null if `display` is

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { RefObject, useRef } from "react";
import React, { useRef } from "react";
import { BreadcrumbsStore } from "../../../stores/BreadcrumbsStore";
import { UPDATE_EVENT } from "../../../stores/AsyncStore";
@ -30,7 +30,7 @@ import { ViewRoomPayload } from "../../../dispatcher/payloads/ViewRoomPayload";
import RoomAvatar from "../avatars/RoomAvatar";
const RecentlyViewedButton: React.FC = () => {
const tooltipRef = useRef() as RefObject<InteractiveTooltip>;
const tooltipRef = useRef<InteractiveTooltip>(null);
const crumbs = useEventEmitterState(BreadcrumbsStore.instance, UPDATE_EVENT, () => BreadcrumbsStore.instance.rooms);
const content = (

View file

@ -134,7 +134,7 @@ export default class ReplyTile extends React.PureComponent<IProps> {
let permalink = "#";
if (this.props.permalinkCreator) {
permalink = this.props.permalinkCreator.forEvent(mxEvent.getId());
permalink = this.props.permalinkCreator.forEvent(mxEvent.getId()!);
}
let sender;

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ChangeEvent, RefObject, useRef, useState } from "react";
import React, { ChangeEvent, useRef, useState } from "react";
import { _t } from "../../../languageHandler";
import AccessibleButton from "../elements/AccessibleButton";
@ -38,7 +38,7 @@ export const SpaceAvatar: React.FC<Pick<IProps, "avatarUrl" | "avatarDisabled" |
avatarDisabled = false,
setAvatar,
}) => {
const avatarUploadRef = useRef() as RefObject<HTMLInputElement>;
const avatarUploadRef = useRef<HTMLInputElement>(null);
const [avatar, setAvatarDataUrl] = useState(avatarUrl); // avatar data url cache
let avatarSection;