Conform more code to strictNullChecks
(#10374)
* Apply `strictNullChecks` to `src/components/views/room_settings/*` * Restore tsconfig.json * Conform more code to `strictNullChecks` * Iterate * Update matrix-widget-api * Conform more code to `strictNullChecks`
This commit is contained in:
parent
9c816bb720
commit
1c9ea423c9
44 changed files with 223 additions and 179 deletions
|
@ -252,10 +252,10 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
}
|
||||
if (isEmpty) {
|
||||
this.formatBarRef.current.hide();
|
||||
this.formatBarRef.current?.hide();
|
||||
}
|
||||
this.setState({
|
||||
autoComplete: this.props.model.autoComplete,
|
||||
autoComplete: this.props.model.autoComplete ?? undefined,
|
||||
// if a change is happening then clear the showVisualBell
|
||||
showVisualBell: diff ? false : this.state.showVisualBell,
|
||||
});
|
||||
|
@ -266,12 +266,16 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
// If the user is entering a command, only consider them typing if it is one which sends a message into the room
|
||||
if (isTyping && this.props.model.parts[0].type === "command") {
|
||||
const { cmd } = parseCommandString(this.props.model.parts[0].text);
|
||||
const command = CommandMap.get(cmd);
|
||||
if (!command || !command.isEnabled() || command.category !== CommandCategories.messages) {
|
||||
const command = CommandMap.get(cmd!);
|
||||
if (!command?.isEnabled() || command.category !== CommandCategories.messages) {
|
||||
isTyping = false;
|
||||
}
|
||||
}
|
||||
SdkContextClass.instance.typingStore.setSelfTyping(this.props.room.roomId, this.props.threadId, isTyping);
|
||||
SdkContextClass.instance.typingStore.setSelfTyping(
|
||||
this.props.room.roomId,
|
||||
this.props.threadId ?? null,
|
||||
isTyping,
|
||||
);
|
||||
|
||||
if (this.props.onChange) {
|
||||
this.props.onChange();
|
||||
|
@ -280,14 +284,14 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private showPlaceholder(): void {
|
||||
// escape single quotes
|
||||
const placeholder = this.props.placeholder.replace(/'/g, "\\'");
|
||||
this.editorRef.current.style.setProperty("--placeholder", `'${placeholder}'`);
|
||||
this.editorRef.current.classList.add("mx_BasicMessageComposer_inputEmpty");
|
||||
const placeholder = this.props.placeholder?.replace(/'/g, "\\'");
|
||||
this.editorRef.current?.style.setProperty("--placeholder", `'${placeholder}'`);
|
||||
this.editorRef.current?.classList.add("mx_BasicMessageComposer_inputEmpty");
|
||||
}
|
||||
|
||||
private hidePlaceholder(): void {
|
||||
this.editorRef.current.classList.remove("mx_BasicMessageComposer_inputEmpty");
|
||||
this.editorRef.current.style.removeProperty("--placeholder");
|
||||
this.editorRef.current?.classList.remove("mx_BasicMessageComposer_inputEmpty");
|
||||
this.editorRef.current?.style.removeProperty("--placeholder");
|
||||
}
|
||||
|
||||
private onCompositionStart = (): void => {
|
||||
|
@ -327,9 +331,9 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
private onCutCopy = (event: ClipboardEvent, type: string): void => {
|
||||
const selection = document.getSelection();
|
||||
const selection = document.getSelection()!;
|
||||
const text = selection.toString();
|
||||
if (text) {
|
||||
if (text && this.editorRef.current) {
|
||||
const { model } = this.props;
|
||||
const range = getRangeForSelection(this.editorRef.current, model, selection);
|
||||
const selectedParts = range.parts.map((p) => p.serialize());
|
||||
|
@ -412,7 +416,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const { model } = this.props;
|
||||
this._isCaretAtEnd = position.isAtEnd(model);
|
||||
this.lastCaret = position.asOffset(model);
|
||||
this.lastSelection = cloneSelection(document.getSelection());
|
||||
this.lastSelection = cloneSelection(document.getSelection()!);
|
||||
}
|
||||
|
||||
private refreshLastCaretIfNeeded(): DocumentOffset | undefined {
|
||||
|
@ -422,7 +426,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
if (!this.editorRef.current) {
|
||||
return;
|
||||
}
|
||||
const selection = document.getSelection();
|
||||
const selection = document.getSelection()!;
|
||||
if (!this.lastSelection || !selectionEquals(this.lastSelection, selection)) {
|
||||
this.lastSelection = cloneSelection(selection);
|
||||
const { caret, text } = getCaretOffsetAndText(this.editorRef.current, selection);
|
||||
|
@ -467,7 +471,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const { isEmpty } = this.props.model;
|
||||
|
||||
this.refreshLastCaretIfNeeded();
|
||||
const selection = document.getSelection();
|
||||
const selection = document.getSelection()!;
|
||||
if (this.hasTextSelected && selection.isCollapsed) {
|
||||
this.hasTextSelected = false;
|
||||
this.formatBarRef.current?.hide();
|
||||
|
@ -485,7 +489,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
const model = this.props.model;
|
||||
let handled = false;
|
||||
|
||||
if (this.state.surroundWith && document.getSelection().type !== "Caret") {
|
||||
if (this.state.surroundWith && document.getSelection()!.type !== "Caret") {
|
||||
// This surrounds the selected text with a character. This is
|
||||
// intentionally left out of the keybinding manager as the keybinds
|
||||
// here shouldn't be changeable
|
||||
|
@ -538,7 +542,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
this.tabCompleteName();
|
||||
handled = true;
|
||||
} else if ([KeyBindingAction.Delete, KeyBindingAction.Backspace].includes(accessibilityAction!)) {
|
||||
this.formatBarRef.current.hide();
|
||||
this.formatBarRef.current?.hide();
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
|
@ -654,7 +658,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
private onAutoCompleteConfirm = (completion: ICompletion): void => {
|
||||
this.modifiedFlag = true;
|
||||
this.props.model.autoComplete.onComponentConfirm(completion);
|
||||
this.props.model.autoComplete?.onComponentConfirm(completion);
|
||||
};
|
||||
|
||||
private onAutoCompleteSelectionChange = (completionIndex: number): void => {
|
||||
|
@ -691,9 +695,9 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener("selectionchange", this.onSelectionChange);
|
||||
this.editorRef.current.removeEventListener("input", this.onInput, true);
|
||||
this.editorRef.current.removeEventListener("compositionstart", this.onCompositionStart, true);
|
||||
this.editorRef.current.removeEventListener("compositionend", this.onCompositionEnd, true);
|
||||
this.editorRef.current?.removeEventListener("input", this.onInput, true);
|
||||
this.editorRef.current?.removeEventListener("compositionstart", this.onCompositionStart, true);
|
||||
this.editorRef.current?.removeEventListener("compositionend", this.onCompositionEnd, true);
|
||||
SettingsStore.unwatchSetting(this.useMarkdownHandle);
|
||||
SettingsStore.unwatchSetting(this.emoticonSettingHandle);
|
||||
SettingsStore.unwatchSetting(this.shouldShowPillAvatarSettingHandle);
|
||||
|
@ -716,10 +720,10 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
this.updateEditorState(this.getInitialCaretPosition());
|
||||
// attach input listener by hand so React doesn't proxy the events,
|
||||
// as the proxied event doesn't support inputType, which we need.
|
||||
this.editorRef.current.addEventListener("input", this.onInput, true);
|
||||
this.editorRef.current.addEventListener("compositionstart", this.onCompositionStart, true);
|
||||
this.editorRef.current.addEventListener("compositionend", this.onCompositionEnd, true);
|
||||
this.editorRef.current.focus();
|
||||
this.editorRef.current?.addEventListener("input", this.onInput, true);
|
||||
this.editorRef.current?.addEventListener("compositionstart", this.onCompositionStart, true);
|
||||
this.editorRef.current?.addEventListener("compositionend", this.onCompositionEnd, true);
|
||||
this.editorRef.current?.focus();
|
||||
}
|
||||
|
||||
private getInitialCaretPosition(): DocumentPosition {
|
||||
|
@ -826,7 +830,7 @@ export default class BasicMessageEditor extends React.Component<IProps, IState>
|
|||
}
|
||||
|
||||
public focus(): void {
|
||||
this.editorRef.current.focus();
|
||||
this.editorRef.current?.focus();
|
||||
}
|
||||
|
||||
public insertMention(userId: string): void {
|
||||
|
|
|
@ -149,7 +149,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
this.dispatcherRef = dis.register(this.onAction);
|
||||
}
|
||||
|
||||
private getRoom(): Room {
|
||||
private getRoom(): Room | null {
|
||||
return this.props.mxClient.getRoom(this.props.editState.getEvent().getRoomId());
|
||||
}
|
||||
|
||||
|
@ -237,10 +237,10 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
}
|
||||
|
||||
private get events(): MatrixEvent[] {
|
||||
const liveTimelineEvents = this.context.liveTimeline.getEvents();
|
||||
const pendingEvents = this.getRoom().getPendingEvents();
|
||||
const liveTimelineEvents = this.context.liveTimeline?.getEvents();
|
||||
const pendingEvents = this.getRoom()?.getPendingEvents();
|
||||
const isInThread = Boolean(this.props.editState.getEvent().getThread());
|
||||
return liveTimelineEvents.concat(isInThread ? [] : pendingEvents);
|
||||
return liveTimelineEvents?.concat(isInThread ? [] : pendingEvents) ?? [];
|
||||
}
|
||||
|
||||
private cancelEdit = (): void => {
|
||||
|
@ -304,10 +304,10 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
});
|
||||
|
||||
// Replace emoticon at the end of the message
|
||||
if (SettingsStore.getValue("MessageComposerInput.autoReplaceEmoji")) {
|
||||
const caret = this.editorRef.current?.getCaret();
|
||||
if (SettingsStore.getValue("MessageComposerInput.autoReplaceEmoji") && this.editorRef.current) {
|
||||
const caret = this.editorRef.current.getCaret();
|
||||
const position = this.model.positionForOffset(caret.offset, caret.atNodeEnd);
|
||||
this.editorRef.current?.replaceEmoticon(position, REGEX_EMOTICON);
|
||||
this.editorRef.current.replaceEmoticon(position, REGEX_EMOTICON);
|
||||
}
|
||||
const editContent = createEditContent(this.model, editedEvent);
|
||||
const newContent = editContent["m.new_content"];
|
||||
|
@ -382,7 +382,7 @@ class EditMessageComposer extends React.Component<IEditMessageComposerProps, ISt
|
|||
// store caret and serialized parts in the
|
||||
// editorstate so it can be restored when the remote echo event tile gets rendered
|
||||
// in case we're currently editing a pending event
|
||||
const sel = document.getSelection();
|
||||
const sel = document.getSelection()!;
|
||||
let caret: DocumentOffset | undefined;
|
||||
if (sel.focusNode) {
|
||||
caret = getCaretOffsetAndText(this.editorRef.current?.editorRef.current, sel).caret;
|
||||
|
|
|
@ -238,7 +238,7 @@ interface IState {
|
|||
|
||||
isQuoteExpanded?: boolean;
|
||||
|
||||
thread: Thread;
|
||||
thread: Thread | null;
|
||||
threadNotification?: NotificationCountType;
|
||||
}
|
||||
|
||||
|
@ -438,12 +438,12 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
if (thread.id === this.props.mxEvent.getId()) {
|
||||
this.updateThread(thread);
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||
room.off(ThreadEvent.New, this.onNewThread);
|
||||
room?.off(ThreadEvent.New, this.onNewThread);
|
||||
}
|
||||
};
|
||||
|
||||
private get thread(): Thread | null {
|
||||
let thread = this.props.mxEvent.getThread();
|
||||
let thread: Thread | undefined = this.props.mxEvent.getThread();
|
||||
/**
|
||||
* Accessing the threads value through the room due to a race condition
|
||||
* that will be solved when there are proper backend support for threads
|
||||
|
@ -452,7 +452,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
*/
|
||||
if (!thread) {
|
||||
const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId());
|
||||
thread = room?.findThreadForEvent(this.props.mxEvent);
|
||||
thread = room?.findThreadForEvent(this.props.mxEvent) ?? undefined;
|
||||
}
|
||||
return thread ?? null;
|
||||
}
|
||||
|
@ -471,7 +471,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
}
|
||||
|
||||
private renderThreadInfo(): React.ReactNode {
|
||||
if (this.state.thread?.id === this.props.mxEvent.getId()) {
|
||||
if (this.state.thread && this.state.thread.id === this.props.mxEvent.getId()) {
|
||||
return (
|
||||
<ThreadSummary mxEvent={this.props.mxEvent} thread={this.state.thread} data-testid="thread-summary" />
|
||||
);
|
||||
|
@ -506,7 +506,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
evt.preventDefault();
|
||||
evt.stopPropagation();
|
||||
const { permalinkCreator, mxEvent } = this.props;
|
||||
const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId());
|
||||
const matrixToUrl = permalinkCreator.forEvent(mxEvent.getId()!);
|
||||
await copyPlaintext(matrixToUrl);
|
||||
};
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ export class UnwrappedEventTile extends React.Component<EventTileProps, IState>
|
|||
const useIRCLayout = this.props.layout === Layout.IRC;
|
||||
const groupTimestamp = !useIRCLayout ? linkedTimestamp : null;
|
||||
const ircTimestamp = useIRCLayout ? linkedTimestamp : null;
|
||||
const bubbleTimestamp = this.props.layout === Layout.Bubble ? messageTimestamp : null;
|
||||
const bubbleTimestamp = this.props.layout === Layout.Bubble ? messageTimestamp : undefined;
|
||||
const groupPadlock = !useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
|
||||
const ircPadlock = useIRCLayout && !isBubbleMessage && this.renderE2EPadlock();
|
||||
|
||||
|
@ -1493,7 +1493,7 @@ class E2ePadlock extends React.Component<IE2ePadlockProps, IE2ePadlockState> {
|
|||
}
|
||||
|
||||
interface ISentReceiptProps {
|
||||
messageState: string; // TODO: Types for message sending state
|
||||
messageState: EventStatus | null;
|
||||
}
|
||||
|
||||
function SentReceipt({ messageState }: ISentReceiptProps): JSX.Element {
|
||||
|
|
|
@ -164,7 +164,7 @@ const NewRoomIntro: React.FC = () => {
|
|||
}
|
||||
|
||||
const creator = room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
|
||||
const creatorName = room?.getMember(creator)?.rawDisplayName || creator;
|
||||
const creatorName = (creator && room?.getMember(creator)?.rawDisplayName) || creator;
|
||||
|
||||
let createdText: string;
|
||||
if (creator === cli.getUserId()) {
|
||||
|
@ -178,7 +178,7 @@ const NewRoomIntro: React.FC = () => {
|
|||
let parentSpace: Room | undefined;
|
||||
if (
|
||||
SpaceStore.instance.activeSpaceRoom?.canInvite(cli.getSafeUserId()) &&
|
||||
SpaceStore.instance.isRoomInSpace(SpaceStore.instance.activeSpace, room.roomId)
|
||||
SpaceStore.instance.isRoomInSpace(SpaceStore.instance.activeSpace!, room.roomId)
|
||||
) {
|
||||
parentSpace = SpaceStore.instance.activeSpaceRoom;
|
||||
}
|
||||
|
|
|
@ -231,7 +231,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
|
||||
contextMenu = (
|
||||
<IconizedContextMenu
|
||||
{...contextMenuBelow(plusMenuHandle.current.getBoundingClientRect())}
|
||||
{...contextMenuBelow(plusMenuHandle.current!.getBoundingClientRect())}
|
||||
onFinished={closePlusMenu}
|
||||
compact
|
||||
>
|
||||
|
@ -357,7 +357,7 @@ const RoomListHeader: React.FC<IProps> = ({ onVisibilityChange }) => {
|
|||
|
||||
contextMenu = (
|
||||
<IconizedContextMenu
|
||||
{...contextMenuBelow(plusMenuHandle.current.getBoundingClientRect())}
|
||||
{...contextMenuBelow(plusMenuHandle.current!.getBoundingClientRect())}
|
||||
onFinished={closePlusMenu}
|
||||
compact
|
||||
>
|
||||
|
|
|
@ -227,12 +227,14 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
// selection must be collapsed and caret at start
|
||||
if (this.editorRef.current?.isSelectionCollapsed() && this.editorRef.current?.isCaretAtStart()) {
|
||||
const events = this.context.liveTimeline
|
||||
.getEvents()
|
||||
?.getEvents()
|
||||
.concat(replyingToThread ? [] : this.props.room.getPendingEvents());
|
||||
const editEvent = findEditableEvent({
|
||||
events,
|
||||
isForward: false,
|
||||
});
|
||||
const editEvent = events
|
||||
? findEditableEvent({
|
||||
events,
|
||||
isForward: false,
|
||||
})
|
||||
: undefined;
|
||||
if (editEvent) {
|
||||
// We're selecting history, so prevent the key event from doing anything else
|
||||
event.preventDefault();
|
||||
|
@ -297,7 +299,7 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
if (events[i].getType() === EventType.RoomMessage) {
|
||||
let shouldReact = true;
|
||||
const lastMessage = events[i];
|
||||
const userId = MatrixClientPeg.get().getUserId();
|
||||
const userId = MatrixClientPeg.get().getSafeUserId();
|
||||
const messageReactions = this.props.room.relations.getChildEventsForEvent(
|
||||
lastMessage.getId()!,
|
||||
RelationType.Annotation,
|
||||
|
@ -307,10 +309,10 @@ export class SendMessageComposer extends React.Component<ISendMessageComposerPro
|
|||
// if we have already sent this reaction, don't redact but don't re-send
|
||||
if (messageReactions) {
|
||||
const myReactionEvents =
|
||||
messageReactions.getAnnotationsBySender()[userId] || new Set<MatrixEvent>();
|
||||
messageReactions.getAnnotationsBySender()?.[userId] || new Set<MatrixEvent>();
|
||||
const myReactionKeys = [...myReactionEvents]
|
||||
.filter((event) => !event.isRedacted())
|
||||
.map((event) => event.getRelation().key);
|
||||
.map((event) => event.getRelation()?.key);
|
||||
shouldReact = !myReactionKeys.includes(reaction);
|
||||
}
|
||||
if (shouldReact) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue