Conform more of the codebase to strictNullChecks
(#10573)
* Conform more of the codebase to `strictNullChecks` * Iterate
This commit is contained in:
parent
b4d7f6b592
commit
605ef084ec
34 changed files with 119 additions and 104 deletions
|
@ -53,7 +53,7 @@ const ConfirmSpaceUserActionDialog: React.FC<IProps> = ({
|
|||
const [roomsToLeave, setRoomsToLeave] = useState<Room[]>([]);
|
||||
const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]);
|
||||
|
||||
let warning: JSX.Element;
|
||||
let warning: JSX.Element | undefined;
|
||||
if (warningMessage) {
|
||||
warning = <div className="mx_ConfirmSpaceUserActionDialog_warning">{warningMessage}</div>;
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useRef, useState } from "react";
|
||||
import React, { RefObject, 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<Field>();
|
||||
const spaceNameField = useRef() as RefObject<Field>;
|
||||
const [alias, setAlias] = useState("");
|
||||
const spaceAliasField = useRef<RoomAliasField>();
|
||||
const spaceAliasField = useRef() as RefObject<RoomAliasField>;
|
||||
const [avatar, setAvatar] = useState<File | undefined>();
|
||||
const [topic, setTopic] = useState<string>("");
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import AccessibleButton from "../elements/AccessibleButton";
|
|||
import AutoHideScrollbar from "../../structures/AutoHideScrollbar";
|
||||
import StyledCheckbox from "../elements/StyledCheckbox";
|
||||
import MatrixClientContext from "../../../contexts/MatrixClientContext";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
|
||||
interface IProps {
|
||||
room: Room;
|
||||
|
@ -65,7 +66,7 @@ const Entry: React.FC<{
|
|||
)}
|
||||
</div>
|
||||
<StyledCheckbox
|
||||
onChange={onChange ? (e) => onChange(e.target.checked) : null}
|
||||
onChange={onChange ? (e) => onChange(e.target.checked) : undefined}
|
||||
checked={checked}
|
||||
disabled={!onChange}
|
||||
/>
|
||||
|
@ -80,7 +81,7 @@ const addAllParents = (set: Set<Room>, room: Room): void => {
|
|||
);
|
||||
|
||||
parents.forEach((parent) => {
|
||||
if (set.has(parent)) return;
|
||||
if (!parent || set.has(parent)) return;
|
||||
set.add(parent);
|
||||
addAllParents(set, parent);
|
||||
});
|
||||
|
@ -97,8 +98,8 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
addAllParents(parents, room);
|
||||
return [
|
||||
Array.from(parents),
|
||||
selected
|
||||
.map((roomId) => {
|
||||
filterBoolean(
|
||||
selected.map((roomId) => {
|
||||
const room = cli.getRoom(roomId);
|
||||
if (!room) {
|
||||
return { roomId, name: roomId } as Room;
|
||||
|
@ -106,8 +107,8 @@ const ManageRestrictedJoinRuleDialog: React.FC<IProps> = ({ room, selected = [],
|
|||
if (room.getMyMembership() !== "join" || !room.isSpaceRoom()) {
|
||||
return room;
|
||||
}
|
||||
})
|
||||
.filter(Boolean),
|
||||
}),
|
||||
),
|
||||
];
|
||||
}, [cli, selected, room]);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { SyntheticEvent, useRef, useState } from "react";
|
||||
import { RefObject, 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<Field>();
|
||||
const fieldRef = useRef() as RefObject<Field>;
|
||||
|
||||
const onSubmit = async (e: SyntheticEvent): Promise<void> => {
|
||||
e.preventDefault();
|
||||
|
|
|
@ -288,8 +288,8 @@ interface IDirectoryOpts {
|
|||
}
|
||||
|
||||
const SpotlightDialog: React.FC<IProps> = ({ initialText = "", initialFilter = null, onFinished }) => {
|
||||
const inputRef = useRef<HTMLInputElement>();
|
||||
const scrollContainerRef = useRef<HTMLDivElement>();
|
||||
const inputRef = useRef() as RefObject<HTMLInputElement>;
|
||||
const scrollContainerRef = useRef() as RefObject<HTMLDivElement>;
|
||||
const cli = MatrixClientPeg.get();
|
||||
const rovingContext = useContext(RovingTabIndexContext);
|
||||
const [query, _setQuery] = useState(initialText);
|
||||
|
|
|
@ -38,7 +38,7 @@ interface IProps {
|
|||
// The text to show as the summary of this event list
|
||||
"summaryText"?: ReactNode;
|
||||
// An array of EventTiles to render when expanded
|
||||
"children": ReactNode[];
|
||||
"children": ReactNode[] | null;
|
||||
// Called when the event list expansion is toggled
|
||||
onToggle?(): void;
|
||||
// The layout currently used
|
||||
|
|
|
@ -45,7 +45,11 @@ interface IProps {
|
|||
}
|
||||
|
||||
interface IState {
|
||||
apps: Partial<{ [id in Container]: IApp[] }>;
|
||||
apps: {
|
||||
[Container.Top]: IApp[];
|
||||
[Container.Center]: IApp[];
|
||||
[Container.Right]?: IApp[];
|
||||
};
|
||||
resizingVertical: boolean; // true when changing the height of the apps drawer
|
||||
resizingHorizontal: boolean; // true when changing the distribution of the width between widgets
|
||||
resizing: boolean;
|
||||
|
@ -203,12 +207,10 @@ export default class AppsDrawer extends React.Component<IProps, IState> {
|
|||
}
|
||||
};
|
||||
|
||||
private getApps = (): Partial<{ [id in Container]: IApp[] }> => {
|
||||
const appsDict: Partial<{ [id in Container]: IApp[] }> = {};
|
||||
appsDict[Container.Top] = WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Top);
|
||||
appsDict[Container.Center] = WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Center);
|
||||
return appsDict;
|
||||
};
|
||||
private getApps = (): IState["apps"] => ({
|
||||
[Container.Top]: WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Top),
|
||||
[Container.Center]: WidgetLayoutStore.instance.getContainerWidgets(this.props.room, Container.Center),
|
||||
});
|
||||
private topApps = (): IApp[] => this.state.apps[Container.Top];
|
||||
private centerApps = (): IApp[] => this.state.apps[Container.Center];
|
||||
|
||||
|
@ -348,7 +350,7 @@ const PersistentVResizer: React.FC<IPersistentResizerProps> = ({
|
|||
resizeNotifier.notifyTimelineHeightChanged();
|
||||
}}
|
||||
onResizeStop={(e, dir, ref, d) => {
|
||||
let newHeight = defaultHeight + d.height;
|
||||
let newHeight = defaultHeight! + d.height;
|
||||
newHeight = percentageOf(newHeight, minHeight, maxHeight) * 100;
|
||||
|
||||
WidgetLayoutStore.instance.setContainerHeight(room, Container.Top, newHeight);
|
||||
|
|
|
@ -231,6 +231,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
private updateEditorState = (selection: Caret, inputType?: string, diff?: IDiff): void => {
|
||||
if (!this.editorRef.current) return;
|
||||
renderModel(this.editorRef.current, this.props.model);
|
||||
if (selection) {
|
||||
// set the caret/selection
|
||||
|
@ -358,6 +359,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private onPaste = (event: ClipboardEvent<HTMLDivElement>): boolean | undefined => {
|
||||
event.preventDefault(); // we always handle the paste ourselves
|
||||
if (!this.editorRef.current) return;
|
||||
if (this.props.onPaste?.(event, this.props.model)) {
|
||||
// to prevent double handling, allow props.onPaste to skip internal onPaste
|
||||
return true;
|
||||
|
@ -377,7 +379,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
this.modifiedFlag = true;
|
||||
const range = getRangeForSelection(this.editorRef.current, model, document.getSelection());
|
||||
const range = getRangeForSelection(this.editorRef.current, model, document.getSelection()!);
|
||||
|
||||
// If the user is pasting a link, and has a range selected which is not a link, wrap the range with the link
|
||||
if (plainText && range.length > 0 && linkify.test(plainText) && !linkify.test(range.text)) {
|
||||
|
@ -388,18 +390,20 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
};
|
||||
|
||||
private onInput = (event: Partial<InputEvent>): void => {
|
||||
if (!this.editorRef.current) return;
|
||||
// ignore any input while doing IME compositions
|
||||
if (this.isIMEComposing) {
|
||||
return;
|
||||
}
|
||||
this.modifiedFlag = true;
|
||||
const sel = document.getSelection();
|
||||
const sel = document.getSelection()!;
|
||||
const { caret, text } = getCaretOffsetAndText(this.editorRef.current, sel);
|
||||
this.props.model.update(text, event.inputType, caret);
|
||||
};
|
||||
|
||||
private insertText(textToInsert: string, inputType = "insertText"): void {
|
||||
const sel = document.getSelection();
|
||||
if (!this.editorRef.current) return;
|
||||
const sel = document.getSelection()!;
|
||||
const { caret, text } = getCaretOffsetAndText(this.editorRef.current, sel);
|
||||
const newText = text.slice(0, caret.offset) + textToInsert + text.slice(caret.offset);
|
||||
caret.offset += textToInsert.length;
|
||||
|
@ -468,6 +472,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
};
|
||||
|
||||
private onSelectionChange = (): void => {
|
||||
if (!this.editorRef.current) return;
|
||||
const { isEmpty } = this.props.model;
|
||||
|
||||
this.refreshLastCaretIfNeeded();
|
||||
|
@ -486,6 +491,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
};
|
||||
|
||||
private onKeyDown = (event: React.KeyboardEvent): void => {
|
||||
if (!this.editorRef.current) return;
|
||||
const model = this.props.model;
|
||||
let handled = false;
|
||||
|
||||
|
@ -497,7 +503,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const selectionRange = getRangeForSelection(
|
||||
this.editorRef.current,
|
||||
this.props.model,
|
||||
document.getSelection(),
|
||||
document.getSelection()!,
|
||||
);
|
||||
// trim the range as we want it to exclude leading/trailing spaces
|
||||
selectionRange.trim();
|
||||
|
@ -745,11 +751,11 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
public onFormatAction = (action: Formatting): void => {
|
||||
if (!this.state.useMarkdown) {
|
||||
if (!this.state.useMarkdown || !this.editorRef.current) {
|
||||
return;
|
||||
}
|
||||
|
||||
const range: Range = getRangeForSelection(this.editorRef.current, this.props.model, document.getSelection());
|
||||
const range: Range = getRangeForSelection(this.editorRef.current, this.props.model, document.getSelection()!);
|
||||
|
||||
this.historyManager.ensureLastChangesPushed(this.props.model);
|
||||
this.modifiedFlag = true;
|
||||
|
|
|
@ -238,9 +238,11 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
|
||||
private get events(): MatrixEvent[] {
|
||||
const liveTimelineEvents = this.context.liveTimeline?.getEvents();
|
||||
const pendingEvents = this.getRoom()?.getPendingEvents();
|
||||
const room = this.getRoom();
|
||||
if (!liveTimelineEvents || !room) return [];
|
||||
const pendingEvents = room.getPendingEvents();
|
||||
const isInThread = Boolean(this.props.editState.getEvent().getThread());
|
||||
return liveTimelineEvents?.concat(isInThread ? [] : pendingEvents) ?? [];
|
||||
return liveTimelineEvents.concat(isInThread ? [] : pendingEvents);
|
||||
}
|
||||
|
||||
private cancelEdit = (): void => {
|
||||
|
|
|
@ -89,15 +89,9 @@ export default class LinkPreviewWidget extends React.Component<IProps> {
|
|||
image = mediaFromMxc(image).getThumbnailOfSourceHttp(imageMaxWidth, imageMaxHeight, "scale");
|
||||
}
|
||||
|
||||
let thumbHeight = imageMaxHeight;
|
||||
if (p["og:image:width"] && p["og:image:height"]) {
|
||||
thumbHeight = ImageUtils.thumbHeight(
|
||||
p["og:image:width"],
|
||||
p["og:image:height"],
|
||||
imageMaxWidth,
|
||||
imageMaxHeight,
|
||||
);
|
||||
}
|
||||
const thumbHeight =
|
||||
ImageUtils.thumbHeight(p["og:image:width"], p["og:image:height"], imageMaxWidth, imageMaxHeight) ??
|
||||
imageMaxHeight;
|
||||
|
||||
let img: JSX.Element | undefined;
|
||||
if (image) {
|
||||
|
|
|
@ -276,7 +276,8 @@ export class MessageComposer extends React.Component<IProps, IState> {
|
|||
if (createEvent?.getId()) createEventId = createEvent.getId();
|
||||
}
|
||||
|
||||
const viaServers = [this.context.tombstone.getSender().split(":").slice(1).join(":")];
|
||||
const sender = this.context.tombstone?.getSender();
|
||||
const viaServers = sender ? [sender.split(":").slice(1).join(":")] : undefined;
|
||||
|
||||
dis.dispatch<ViewRoomPayload>({
|
||||
action: Action.ViewRoom,
|
||||
|
|
|
@ -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, useContext, useRef } from "react";
|
||||
import React, { createContext, MouseEventHandler, ReactElement, ReactNode, RefObject, 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<HTMLInputElement>();
|
||||
const uploadInput = useRef() as RefObject<HTMLInputElement>;
|
||||
|
||||
const onUploadClick = (): void => {
|
||||
if (cli?.isGuest()) {
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useRef } from "react";
|
||||
import React, { RefObject, 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<InteractiveTooltip>();
|
||||
const tooltipRef = useRef() as RefObject<InteractiveTooltip>;
|
||||
const crumbs = useEventEmitterState(BreadcrumbsStore.instance, UPDATE_EVENT, () => BreadcrumbsStore.instance.rooms);
|
||||
|
||||
const content = (
|
||||
|
|
|
@ -33,7 +33,7 @@ function cancelQuoting(context: TimelineRenderingType): void {
|
|||
}
|
||||
|
||||
interface IProps {
|
||||
permalinkCreator: RoomPermalinkCreator;
|
||||
permalinkCreator?: RoomPermalinkCreator;
|
||||
replyToEvent?: MatrixEvent;
|
||||
}
|
||||
|
||||
|
|
|
@ -73,7 +73,7 @@ interface IProps {
|
|||
interface IState {
|
||||
defaultIdServer?: string;
|
||||
currentClientIdServer?: string;
|
||||
idServer?: string;
|
||||
idServer: string;
|
||||
error?: string;
|
||||
busy: boolean;
|
||||
disconnectBusy: boolean;
|
||||
|
|
|
@ -17,6 +17,7 @@ limitations under the License.
|
|||
import React, { useCallback, useMemo, useState } from "react";
|
||||
import { JoinRule } from "matrix-js-sdk/src/@types/partials";
|
||||
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
||||
|
||||
import { _t } from "../../../../../languageHandler";
|
||||
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
|
||||
|
@ -33,15 +34,15 @@ interface ElementCallSwitchProps {
|
|||
|
||||
const ElementCallSwitch: React.FC<ElementCallSwitchProps> = ({ roomId }) => {
|
||||
const room = useMemo(() => MatrixClientPeg.get().getRoom(roomId), [roomId]);
|
||||
const isPublic = useMemo(() => room.getJoinRule() === JoinRule.Public, [room]);
|
||||
const isPublic = useMemo(() => room?.getJoinRule() === JoinRule.Public, [room]);
|
||||
const [content, events, maySend] = useRoomState(
|
||||
room,
|
||||
useCallback((state) => {
|
||||
room ?? undefined,
|
||||
useCallback((state: RoomState) => {
|
||||
const content = state?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent();
|
||||
return [
|
||||
content ?? {},
|
||||
content?.["events"] ?? {},
|
||||
state?.maySendStateEvent(EventType.RoomPowerLevels, MatrixClientPeg.get().getUserId()),
|
||||
state?.maySendStateEvent(EventType.RoomPowerLevels, MatrixClientPeg.get().getSafeUserId()),
|
||||
];
|
||||
}, []),
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { ChangeEvent, useRef, useState } from "react";
|
||||
import React, { ChangeEvent, RefObject, 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<HTMLInputElement>();
|
||||
const avatarUploadRef = useRef() as RefObject<HTMLInputElement>;
|
||||
const [avatar, setAvatarDataUrl] = useState(avatarUrl); // avatar data url cache
|
||||
|
||||
let avatarSection;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue