Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Conform more code to strictNullChecks (#10368 #10368

Merged
merged 2 commits into from
Mar 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion src/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,19 @@ export type ComponentType = React.ComponentType<{
onFinished?(...args: any): void;
}>;

type Defaultize<P, D> = P extends any
? string extends keyof P
? P
: Pick<P, Exclude<keyof P, keyof D>> &
Partial<Pick<P, Extract<keyof P, keyof D>>> &
Partial<Pick<D, Exclude<keyof D, keyof P>>>
: never;

// Generic type which returns the props of the Modal component with the onFinished being optional.
export type ComponentProps<C extends ComponentType> = Omit<React.ComponentProps<C>, "onFinished"> &
export type ComponentProps<C extends ComponentType> = Defaultize<
Omit<React.ComponentProps<C>, "onFinished">,
C["defaultProps"]
> &
Partial<Pick<React.ComponentProps<C>, "onFinished">>;

export interface IModal<C extends ComponentType> {
Expand Down
38 changes: 19 additions & 19 deletions src/components/structures/RoomView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
});
};

private onPageUnload = (event: BeforeUnloadEvent): string => {
private onPageUnload = (event: BeforeUnloadEvent): string | undefined => {
if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
return (event.returnValue = _t("You seem to be uploading files, are you sure you want to quit?"));
} else if (this.getCallForRoom() && this.state.callState !== "ended") {
Expand All @@ -1034,7 +1034,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const action = getKeyBindingsManager().getRoomAction(ev);
switch (action) {
case KeyBindingAction.DismissReadMarker:
this.messagePanel.forgetReadMarker();
this.messagePanel?.forgetReadMarker();
this.jumpToLiveTimeline();
handled = true;
break;
Expand Down Expand Up @@ -1067,7 +1067,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {

if (!roomId) return;
const call = this.getCallForRoom();
this.setState({ callState: call ? call.state : null });
this.setState({ callState: call?.state });
};

private onAction = async (payload: ActionPayload): Promise<void> => {
Expand All @@ -1087,7 +1087,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
ContentMessages.sharedInstance().sendContentListToRoom(
[payload.file],
this.state.room.roomId,
null,
undefined,
this.context.client,
);
break;
Expand Down Expand Up @@ -1117,7 +1117,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
if (!this.state.matrixClientIsReady) {
this.setState(
{
matrixClientIsReady: this.context.client?.isInitialSyncComplete(),
matrixClientIsReady: !!this.context.client?.isInitialSyncComplete(),
},
() => {
// send another "initial" RVS update to trigger peeking if needed
Expand All @@ -1137,7 +1137,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
case Action.EditEvent: {
// Quit early if we're trying to edit events in wrong rendering context
if (payload.timelineRenderingType !== this.state.timelineRenderingType) return;
const editState = payload.event ? new EditorStateTransfer(payload.event) : null;
const editState = payload.event ? new EditorStateTransfer(payload.event) : undefined;
this.setState({ editState }, () => {
if (payload.event) {
this.messagePanel?.scrollToEventIfNeeded(payload.event.getId());
Expand Down Expand Up @@ -1194,7 +1194,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {

private onRoomTimeline = (
ev: MatrixEvent,
room: Room | null,
room: Room | undefined,
toStartOfTimeline: boolean,
removed: boolean,
data?: IRoomTimelineData,
Expand Down Expand Up @@ -1228,7 +1228,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
this.handleEffects(ev);
}

if (ev.getSender() !== this.context.client.credentials.userId) {
if (ev.getSender() !== this.context.client.getSafeUserId()) {
// update unread count when scrolled up
if (!this.state.search && this.state.atEndOfLiveTimeline) {
// no change
Expand Down Expand Up @@ -1325,7 +1325,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
};

private getRoomTombstone(room = this.state.room): MatrixEvent | undefined {
return room?.currentState.getStateEvents(EventType.RoomTombstone, "");
return room?.currentState.getStateEvents(EventType.RoomTombstone, "") ?? undefined;
}

private async calculateRecommendedVersion(room: Room): Promise<void> {
Expand All @@ -1336,7 +1336,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {

private async loadMembersIfJoined(room: Room): Promise<void> {
// lazy load members if enabled
if (this.context.client.hasLazyLoadMembersEnabled()) {
if (this.context.client?.hasLazyLoadMembersEnabled()) {
if (room && room.getMyMembership() === "join") {
try {
await room.loadMembersIfNeeded();
Expand Down Expand Up @@ -1415,7 +1415,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
};

private async updateE2EStatus(room: Room): Promise<void> {
if (!this.context.client.isRoomEncrypted(room.roomId)) return;
if (!this.context.client?.isRoomEncrypted(room.roomId)) return;

// If crypto is not currently enabled, we aren't tracking devices at all,
// so we don't know what the answer is. Let's error on the safe side and show
Expand Down Expand Up @@ -2093,7 +2093,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
// We have successfully loaded this room, and are not previewing.
// Display the "normal" room view.

let activeCall = null;
let activeCall: MatrixCall | null = null;
{
// New block because this variable doesn't need to hang around for the rest of the function
const call = this.getCallForRoom();
Expand All @@ -2102,7 +2102,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
}
}

let statusBar;
let statusBar: JSX.Element | undefined;
let isStatusAreaExpanded = true;

if (ContentMessages.sharedInstance().getCurrentUploads().length > 0) {
Expand Down Expand Up @@ -2301,7 +2301,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
/>
);

let topUnreadMessagesBar = null;
let topUnreadMessagesBar: JSX.Element | undefined;
// Do not show TopUnreadMessagesBar if we have search results showing, it makes no sense
if (this.state.showTopUnreadMessagesBar && !this.state.search) {
topUnreadMessagesBar = (
Expand Down Expand Up @@ -2342,7 +2342,7 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {

const showChatEffects = SettingsStore.getValue("showChatEffects");

let mainSplitBody: React.ReactFragment;
let mainSplitBody: JSX.Element | undefined;
let mainSplitContentClassName: string;
// Decide what to show in the main split
switch (this.state.mainSplitContentType) {
Expand Down Expand Up @@ -2396,10 +2396,10 @@ export class RoomView extends React.Component<IRoomProps, IRoomState> {
const mainSplitContentClasses = classNames("mx_RoomView_body", mainSplitContentClassName);

let excludedRightPanelPhaseButtons = [RightPanelPhases.Timeline];
let onAppsClick = this.onAppsClick;
let onForgetClick = this.onForgetClick;
let onSearchClick = this.onSearchClick;
let onInviteClick = null;
let onAppsClick: (() => void) | null = this.onAppsClick;
let onForgetClick: (() => void) | null = this.onForgetClick;
let onSearchClick: (() => void) | null = this.onSearchClick;
let onInviteClick: (() => void) | null = null;
let viewingCall = false;

// Simplify the header for other main split types
Expand Down
62 changes: 29 additions & 33 deletions src/components/structures/SpaceHierarchy.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -100,9 +100,9 @@ const Tile: React.FC<ITileProps> = ({
children,
}) => {
const cli = useContext(MatrixClientContext);
const [joinedRoom, setJoinedRoom] = useState<Room>(() => {
const [joinedRoom, setJoinedRoom] = useState<Room | undefined>(() => {
const cliRoom = cli.getRoom(room.room_id);
return cliRoom?.getMyMembership() === "join" ? cliRoom : null;
return cliRoom?.getMyMembership() === "join" ? cliRoom : undefined;
});
const joinedRoomName = useTypedEventEmitterState(joinedRoom, RoomEvent.Name, (room) => room?.name);
const name =
Expand Down Expand Up @@ -264,9 +264,9 @@ const Tile: React.FC<ITileProps> = ({
</React.Fragment>
);

let childToggle: JSX.Element;
let childSection: JSX.Element;
let onKeyDown: KeyboardEventHandler;
let childToggle: JSX.Element | undefined;
let childSection: JSX.Element | undefined;
let onKeyDown: KeyboardEventHandler | undefined;
if (children) {
// the chevron is purposefully a div rather than a button as it should be ignored for a11y
childToggle = (
Expand Down Expand Up @@ -386,32 +386,28 @@ export const showRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: st
});
};

export const joinRoom = (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string): Promise<unknown> => {
export const joinRoom = async (cli: MatrixClient, hierarchy: RoomHierarchy, roomId: string): Promise<unknown> => {
// Don't let the user view a room they won't be able to either peek or join:
// fail earlier so they don't have to click back to the directory.
if (cli.isGuest()) {
defaultDispatcher.dispatch({ action: "require_registration" });
return;
}

const prom = cli.joinRoom(roomId, {
viaServers: Array.from(hierarchy.viaMap.get(roomId) || []),
});

prom.then(
() => {
defaultDispatcher.dispatch<JoinRoomReadyPayload>({
action: Action.JoinRoomReady,
roomId,
metricsTrigger: "SpaceHierarchy",
});
},
(err) => {
SdkContextClass.instance.roomViewStore.showJoinRoomError(err, roomId);
},
);
try {
await cli.joinRoom(roomId, {
viaServers: Array.from(hierarchy.viaMap.get(roomId) || []),
});
} catch (err) {
SdkContextClass.instance.roomViewStore.showJoinRoomError(err, roomId);
return;
}

return prom;
defaultDispatcher.dispatch<JoinRoomReadyPayload>({
action: Action.JoinRoomReady,
roomId,
metricsTrigger: "SpaceHierarchy",
});
};

interface IHierarchyLevelProps {
Expand All @@ -433,7 +429,7 @@ export const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom, hierarchy:
);

// Pick latest room that is actually part of the hierarchy
let cliRoom = null;
let cliRoom: Room | null = null;
for (let idx = history.length - 1; idx >= 0; --idx) {
if (hierarchy.roomMap.get(history[idx].roomId)) {
cliRoom = history[idx];
Expand All @@ -448,7 +444,7 @@ export const toLocalRoom = (cli: MatrixClient, room: IHierarchyRoom, hierarchy:
room_type: cliRoom.getType(),
name: cliRoom.name,
topic: cliRoom.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent().topic,
avatar_url: cliRoom.getMxcAvatarUrl(),
avatar_url: cliRoom.getMxcAvatarUrl() ?? undefined,
canonical_alias: cliRoom.getCanonicalAlias() ?? undefined,
aliases: cliRoom.getAltAliases(),
world_readable:
Expand Down Expand Up @@ -476,7 +472,7 @@ export const HierarchyLevel: React.FC<IHierarchyLevelProps> = ({
}) => {
const cli = useContext(MatrixClientContext);
const space = cli.getRoom(root.room_id);
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
const hasPermissions = space?.currentState.maySendStateEvent(EventType.SpaceChild, cli.getSafeUserId());

const sortedChildren = sortBy(root.children_state, (ev) => {
return getChildOrder(ev.content.order, ev.origin_server_ts, ev.state_key);
Expand Down Expand Up @@ -579,7 +575,7 @@ export const useRoomHierarchy = (

const loadMore = useCallback(
async (pageSize?: number): Promise<void> => {
if (hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return;
if (!hierarchy || hierarchy.loading || !hierarchy.canLoadMore || hierarchy.noSupport || error) return;
await hierarchy.load(pageSize).catch(setError);
setRooms(hierarchy.rooms);
},
Expand Down Expand Up @@ -673,7 +669,7 @@ const ManageButtons: React.FC<IManageButtonsProps> = ({ hierarchy, selected, set
onClick={async (): Promise<void> => {
setRemoving(true);
try {
const userId = cli.getUserId();
const userId = cli.getSafeUserId();
for (const [parentId, childId] of selectedRelations) {
await cli.sendStateEvent(parentId, EventType.SpaceChild, {}, childId);

Expand Down Expand Up @@ -759,7 +755,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
const visited = new Set<string>();
const queue = [...directMatches.map((r) => r.room_id)];
while (queue.length) {
const roomId = queue.pop();
const roomId = queue.pop()!;
visited.add(roomId);
hierarchy.backRefs.get(roomId)?.forEach((parentId) => {
if (!visited.has(parentId)) {
Expand Down Expand Up @@ -797,7 +793,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
return;
}

const parentSet = selected.get(parentId);
const parentSet = selected.get(parentId)!;
if (!parentSet.has(childId)) {
setSelected(new Map(selected.set(parentId, new Set([...parentSet, childId]))));
return;
Expand All @@ -816,9 +812,9 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
} else {
const hasPermissions =
space?.getMyMembership() === "join" &&
space.currentState.maySendStateEvent(EventType.SpaceChild, cli.getUserId());
space.currentState.maySendStateEvent(EventType.SpaceChild, cli.getSafeUserId());

let results: JSX.Element;
let results: JSX.Element | undefined;
if (filteredRoomSet.size) {
results = (
<>
Expand All @@ -843,7 +839,7 @@ const SpaceHierarchy: React.FC<IProps> = ({ space, initialText = "", showRoom, a
);
}

let loader: JSX.Element;
let loader: JSX.Element | undefined;
if (hierarchy.canLoadMore) {
loader = (
<div ref={loaderRef}>
Expand Down
12 changes: 6 additions & 6 deletions src/components/views/dialogs/BugReportDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ interface IProps {
interface IState {
sendLogs: boolean;
busy: boolean;
err: string;
err: string | null;
issueUrl: string;
text: string;
progress: string;
progress: string | null;
downloadBusy: boolean;
downloadProgress: string;
downloadProgress: string | null;
}

export default class BugReportDialog extends React.Component<IProps, IState> {
Expand Down Expand Up @@ -181,12 +181,12 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
};

public render(): React.ReactNode {
let error = null;
let error: JSX.Element | undefined;
if (this.state.err) {
error = <div className="error">{this.state.err}</div>;
}

let progress = null;
let progress: JSX.Element | undefined;
if (this.state.busy) {
progress = (
<div className="progress">
Expand All @@ -196,7 +196,7 @@ export default class BugReportDialog extends React.Component<IProps, IState> {
);
}

let warning;
let warning: JSX.Element | undefined;
if (window.Modernizr && Object.values(window.Modernizr).some((support) => support === false)) {
warning = (
<p>
Expand Down
Loading