", null, {
+ {_t("Forgotten or lost all recovery methods?
", undefined, {
a: (sub) => (
);
}
} else if (phase === Phase.Done) {
- let message;
+ let message: JSX.Element;
if (this.state.backupInfo) {
message = (
diff --git a/src/components/structures/auth/SoftLogout.tsx b/src/components/structures/auth/SoftLogout.tsx
index 46e8568697..3eb997c843 100644
--- a/src/components/structures/auth/SoftLogout.tsx
+++ b/src/components/structures/auth/SoftLogout.tsx
@@ -23,7 +23,7 @@ import { _t } from "../../../languageHandler";
import dis from "../../../dispatcher/dispatcher";
import * as Lifecycle from "../../../Lifecycle";
import Modal from "../../../Modal";
-import { MatrixClientPeg } from "../../../MatrixClientPeg";
+import { IMatrixClientCreds, MatrixClientPeg } from "../../../MatrixClientPeg";
import { sendLoginRequest } from "../../../Login";
import AuthPage from "../../views/auth/AuthPage";
import { SSO_HOMESERVER_URL_KEY, SSO_ID_SERVER_URL_KEY } from "../../../BasePlatform";
@@ -159,7 +159,7 @@ export default class SoftLogout extends React.Component {
device_id: MatrixClientPeg.get().getDeviceId(),
};
- let credentials = null;
+ let credentials: IMatrixClientCreds;
try {
credentials = await sendLoginRequest(hsUrl, isUrl, loginType, loginParams);
} catch (e) {
@@ -192,7 +192,7 @@ export default class SoftLogout extends React.Component {
device_id: MatrixClientPeg.get().getDeviceId(),
};
- let credentials = null;
+ let credentials: IMatrixClientCreds;
try {
credentials = await sendLoginRequest(hsUrl, isUrl, loginType, loginParams);
} catch (e) {
@@ -212,7 +212,7 @@ export default class SoftLogout extends React.Component {
}
private renderPasswordForm(introText: Optional): JSX.Element {
- let error: JSX.Element = null;
+ let error: JSX.Element | undefined;
if (this.state.errorText) {
error = {this.state.errorText} ;
}
@@ -267,7 +267,7 @@ export default class SoftLogout extends React.Component {
return ;
}
- let introText = null; // null is translated to something area specific in this function
+ let introText: string | null = null; // null is translated to something area specific in this function
if (this.state.keyBackupNeeded) {
introText = _t(
"Regain access to your account and recover encryption keys stored in this session. " +
diff --git a/src/components/structures/auth/header/AuthHeaderDisplay.tsx b/src/components/structures/auth/header/AuthHeaderDisplay.tsx
index 75c0feb82c..121859498d 100644
--- a/src/components/structures/auth/header/AuthHeaderDisplay.tsx
+++ b/src/components/structures/auth/header/AuthHeaderDisplay.tsx
@@ -27,7 +27,7 @@ interface Props {
export function AuthHeaderDisplay({ title, icon, serverPicker, children }: PropsWithChildren): JSX.Element {
const context = useContext(AuthHeaderContext);
if (!context) {
- return null;
+ return <>>;
}
const current = context.state.length ? context.state[0] : null;
return (
diff --git a/src/components/views/context_menus/RoomContextMenu.tsx b/src/components/views/context_menus/RoomContextMenu.tsx
index 03914b329e..3b335b4dcd 100644
--- a/src/components/views/context_menus/RoomContextMenu.tsx
+++ b/src/components/views/context_menus/RoomContextMenu.tsx
@@ -61,7 +61,7 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => {
RoomListStore.instance.getTagsForRoom(room),
);
- let leaveOption: JSX.Element;
+ let leaveOption: JSX.Element | undefined;
if (roomTags.includes(DefaultTagID.Archived)) {
const onForgetRoomClick = (ev: ButtonEvent): void => {
ev.preventDefault();
@@ -112,7 +112,7 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => {
const isVideoRoom =
videoRoomsEnabled && (room.isElementVideoRoom() || (elementCallVideoRoomsEnabled && room.isCallRoom()));
- let inviteOption: JSX.Element;
+ let inviteOption: JSX.Element | undefined;
if (room.canInvite(cli.getUserId()!) && !isDm) {
const onInviteClick = (ev: ButtonEvent): void => {
ev.preventDefault();
@@ -136,9 +136,9 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => {
);
}
- let favouriteOption: JSX.Element;
- let lowPriorityOption: JSX.Element;
- let notificationOption: JSX.Element;
+ let favouriteOption: JSX.Element | undefined;
+ let lowPriorityOption: JSX.Element | undefined;
+ let notificationOption: JSX.Element | undefined;
if (room.getMyMembership() === "join") {
const isFavorite = roomTags.includes(DefaultTagID.Favourite);
favouriteOption = (
@@ -208,8 +208,8 @@ const RoomContextMenu: React.FC = ({ room, onFinished, ...props }) => {
);
}
- let peopleOption: JSX.Element;
- let copyLinkOption: JSX.Element;
+ let peopleOption: JSX.Element | undefined;
+ let copyLinkOption: JSX.Element | undefined;
if (!isDm) {
peopleOption = (
= ({ room, onFinished, ...props }) => {
);
}
- let filesOption: JSX.Element;
+ let filesOption: JSX.Element | undefined;
if (!isVideoRoom) {
filesOption = (
= ({ room, onFinished, ...props }) => {
}
const pinningEnabled = useFeatureEnabled("feature_pinning");
- const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
+ const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
- let pinsOption: JSX.Element;
+ let pinsOption: JSX.Element | undefined;
if (pinningEnabled && !isVideoRoom) {
pinsOption = (
= ({ room, onFinished, ...props }) => {
);
}
- let widgetsOption: JSX.Element;
+ let widgetsOption: JSX.Element | undefined;
if (!isVideoRoom) {
widgetsOption = (
= ({ room, onFinished, ...props }) => {
);
}
- let exportChatOption: JSX.Element;
+ let exportChatOption: JSX.Element | undefined;
if (!isVideoRoom) {
exportChatOption = (
= ({ room, checked, onChange }) => {
return (
@@ -67,7 +68,7 @@ export const Entry: React.FC<{
)}
{room.name}
onChange(e.currentTarget.checked) : null}
+ onChange={onChange ? (e) => onChange(e.currentTarget.checked) : undefined}
checked={checked}
disabled={!onChange}
/>
@@ -150,8 +151,8 @@ export const AddExistingToSpace: React.FC = ({
});
const [selectedToAdd, setSelectedToAdd] = useState(new Set());
- const [progress, setProgress] = useState(null);
- const [error, setError] = useState(null);
+ const [progress, setProgress] = useState(null);
+ const [error, setError] = useState(null);
const [query, setQuery] = useState("");
const lcQuery = query.toLowerCase().trim();
@@ -164,7 +165,7 @@ export const AddExistingToSpace: React.FC = ({
if (lcQuery) {
const matcher = new QueryMatcher(visibleRooms, {
keys: ["name"],
- funcs: [(r) => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)],
+ funcs: [(r) => filterBoolean([r.getCanonicalAlias(), ...r.getAltAliases()])],
shouldMatchWordsOnly: false,
});
@@ -172,7 +173,7 @@ export const AddExistingToSpace: React.FC = ({
}
const joinRule = space.getJoinRule();
- return sortRooms(rooms).reduce(
+ return sortRooms(rooms).reduce<[spaces: Room[], rooms: Room[], dms: Room[]]>(
(arr, room) => {
if (room.isSpaceRoom()) {
if (room !== space && !existingSubspacesSet.has(room)) {
@@ -289,7 +290,7 @@ export const AddExistingToSpace: React.FC = ({
}
setSelectedToAdd(new Set(selectedToAdd));
}
- : null;
+ : undefined;
// only count spaces when alone as they're shown on a separate modal all on their own
const numSpaces = spacesRenderer && !dmsRenderer && !roomsRenderer ? spaces.length : 0;
@@ -373,7 +374,7 @@ const defaultRendererFactory =
? (checked: boolean) => {
onChange(checked, room);
}
- : null
+ : undefined
}
/>
)}
@@ -397,7 +398,7 @@ export const SubspaceSelector: React.FC = ({ title, spac
return [
space,
...SpaceStore.instance.getChildSpaces(space.roomId).filter((space) => {
- return space.currentState.maySendStateEvent(EventType.SpaceChild, space.client.credentials.userId);
+ return space.currentState.maySendStateEvent(EventType.SpaceChild, space.client.getSafeUserId());
}),
];
}, [space]);
diff --git a/src/components/views/dialogs/BaseDialog.tsx b/src/components/views/dialogs/BaseDialog.tsx
index 0def4f1943..5068ef075d 100644
--- a/src/components/views/dialogs/BaseDialog.tsx
+++ b/src/components/views/dialogs/BaseDialog.tsx
@@ -153,12 +153,11 @@ export default class BaseDialog extends React.Component {
return (
-
+ {this.props.screenName && }
diff --git a/src/components/views/dialogs/InviteDialog.tsx b/src/components/views/dialogs/InviteDialog.tsx
index d5563d0e26..7ddd9e8b4f 100644
--- a/src/components/views/dialogs/InviteDialog.tsx
+++ b/src/components/views/dialogs/InviteDialog.tsx
@@ -74,6 +74,7 @@ import { InviteKind } from "./InviteDialogTypes";
import Modal from "../../../Modal";
import dis from "../../../dispatcher/dispatcher";
import { privateShouldBeEncrypted } from "../../../utils/rooms";
+import { NonEmptyArray } from "../../../@types/common";
// we have a number of types defined from the Matrix spec which can't reasonably be altered here.
/* eslint-disable camelcase */
@@ -1421,10 +1422,9 @@ export default class InviteDialog extends React.PureComponent = [
new Tab(TabId.UserDirectory, _td("User Directory"), "mx_InviteDialog_userDirectoryIcon", usersSection),
- );
+ ];
const backspaceButton = ;
diff --git a/src/components/views/dialogs/RoomSettingsDialog.tsx b/src/components/views/dialogs/RoomSettingsDialog.tsx
index b8e31c1540..d1ddc62683 100644
--- a/src/components/views/dialogs/RoomSettingsDialog.tsx
+++ b/src/components/views/dialogs/RoomSettingsDialog.tsx
@@ -34,6 +34,7 @@ import BaseDialog from "./BaseDialog";
import { Action } from "../../../dispatcher/actions";
import { VoipRoomSettingsTab } from "../settings/tabs/room/VoipRoomSettingsTab";
import { ActionPayload } from "../../../dispatcher/payloads";
+import { NonEmptyArray } from "../../../@types/common";
export const ROOM_GENERAL_TAB = "ROOM_GENERAL_TAB";
export const ROOM_VOIP_TAB = "ROOM_VOIP_TAB";
@@ -85,11 +86,11 @@ export default class RoomSettingsDialog extends React.Component
private onRoomName = (): void => {
this.setState({
- roomName: MatrixClientPeg.get().getRoom(this.props.roomId).name,
+ roomName: MatrixClientPeg.get().getRoom(this.props.roomId)?.name ?? "",
});
};
- private getTabs(): Tab[] {
+ private getTabs(): NonEmptyArray {
const tabs: Tab[] = [];
tabs.push(
@@ -178,7 +179,7 @@ export default class RoomSettingsDialog extends React.Component
);
}
- return tabs;
+ return tabs as NonEmptyArray;
}
public render(): React.ReactNode {
diff --git a/src/components/views/dialogs/SpacePreferencesDialog.tsx b/src/components/views/dialogs/SpacePreferencesDialog.tsx
index a66d0aad66..3042405cef 100644
--- a/src/components/views/dialogs/SpacePreferencesDialog.tsx
+++ b/src/components/views/dialogs/SpacePreferencesDialog.tsx
@@ -26,6 +26,7 @@ import SettingsStore from "../../../settings/SettingsStore";
import { SettingLevel } from "../../../settings/SettingLevel";
import RoomName from "../elements/RoomName";
import { SpacePreferenceTab } from "../../../dispatcher/payloads/OpenSpacePreferencesPayload";
+import { NonEmptyArray } from "../../../@types/common";
interface IProps {
space: Room;
@@ -69,7 +70,7 @@ const SpacePreferencesAppearanceTab: React.FC> = ({ space
};
const SpacePreferencesDialog: React.FC = ({ space, initialTabId, onFinished }) => {
- const tabs = [
+ const tabs: NonEmptyArray = [
new Tab(
SpacePreferenceTab.Appearance,
_td("Appearance"),
diff --git a/src/components/views/dialogs/SpaceSettingsDialog.tsx b/src/components/views/dialogs/SpaceSettingsDialog.tsx
index e7d7489b08..e67e6f21ff 100644
--- a/src/components/views/dialogs/SpaceSettingsDialog.tsx
+++ b/src/components/views/dialogs/SpaceSettingsDialog.tsx
@@ -30,6 +30,7 @@ import { UIFeature } from "../../../settings/UIFeature";
import AdvancedRoomSettingsTab from "../settings/tabs/room/AdvancedRoomSettingsTab";
import RolesRoomSettingsTab from "../settings/tabs/room/RolesRoomSettingsTab";
import { Action } from "../../../dispatcher/actions";
+import { NonEmptyArray } from "../../../@types/common";
export enum SpaceSettingsTab {
General = "SPACE_GENERAL_TAB",
@@ -79,7 +80,7 @@ const SpaceSettingsDialog: React.FC = ({ matrixClient: cli, space, onFin
,
)
: null,
- ].filter(Boolean);
+ ].filter(Boolean) as NonEmptyArray;
}, [cli, space, onFinished]);
return (
diff --git a/src/components/views/dialogs/UserSettingsDialog.tsx b/src/components/views/dialogs/UserSettingsDialog.tsx
index 07a795f04d..f8cbae2e9f 100644
--- a/src/components/views/dialogs/UserSettingsDialog.tsx
+++ b/src/components/views/dialogs/UserSettingsDialog.tsx
@@ -36,6 +36,7 @@ import SidebarUserSettingsTab from "../settings/tabs/user/SidebarUserSettingsTab
import KeyboardUserSettingsTab from "../settings/tabs/user/KeyboardUserSettingsTab";
import SessionManagerTab from "../settings/tabs/user/SessionManagerTab";
import { UserTab } from "./UserTab";
+import { NonEmptyArray } from "../../../@types/common";
interface IProps {
initialTabId?: UserTab;
@@ -80,7 +81,7 @@ export default class UserSettingsDialog extends React.Component
this.setState({ newSessionManagerEnabled: newValue });
};
- private getTabs(): Tab[] {
+ private getTabs(): NonEmptyArray {
const tabs: Tab[] = [];
tabs.push(
@@ -207,7 +208,7 @@ export default class UserSettingsDialog extends React.Component
),
);
- return tabs;
+ return tabs as NonEmptyArray;
}
public render(): React.ReactNode {
diff --git a/src/components/views/elements/DesktopCapturerSourcePicker.tsx b/src/components/views/elements/DesktopCapturerSourcePicker.tsx
index ccb64ead30..cf8f6b018d 100644
--- a/src/components/views/elements/DesktopCapturerSourcePicker.tsx
+++ b/src/components/views/elements/DesktopCapturerSourcePicker.tsx
@@ -23,6 +23,7 @@ import DialogButtons from "./DialogButtons";
import AccessibleButton from "./AccessibleButton";
import TabbedView, { Tab, TabLocation } from "../../structures/TabbedView";
import PlatformPeg from "../../../PlatformPeg";
+import { NonEmptyArray } from "../../../@types/common";
export function getDesktopCapturerSources(): Promise> {
const options: GetSourcesOptions = {
@@ -80,7 +81,7 @@ export interface PickerIState {
selectedSource: DesktopCapturerSource | null;
}
export interface PickerIProps {
- onFinished(sourceId: string): void;
+ onFinished(sourceId?: string): void;
}
export default class DesktopCapturerSourcePicker extends React.Component {
@@ -129,7 +130,7 @@ export default class DesktopCapturerSourcePicker extends React.Component {
- this.props.onFinished(null);
+ this.props.onFinished();
};
private getTab(type: "screen" | "window", label: string): Tab {
@@ -150,7 +151,7 @@ export default class DesktopCapturerSourcePicker extends React.Component = [
this.getTab("screen", _t("Share entire screen")),
this.getTab("window", _t("Application window")),
];
diff --git a/src/components/views/elements/PowerSelector.tsx b/src/components/views/elements/PowerSelector.tsx
index f7a4ab4b81..6bfaf52f67 100644
--- a/src/components/views/elements/PowerSelector.tsx
+++ b/src/components/views/elements/PowerSelector.tsx
@@ -25,7 +25,7 @@ import { objectHasDiff } from "../../../utils/objects";
const CUSTOM_VALUE = "SELECT_VALUE_CUSTOM";
-interface IProps {
+interface Props {
value: number;
// The maximum value that can be set with the power selector
maxValue: number;
@@ -35,13 +35,14 @@ interface IProps {
// should the user be able to change the value? false by default.
disabled?: boolean;
- onChange?: (value: number, powerLevelKey: string) => void;
-
- // Optional key to pass as the second argument to `onChange`
- powerLevelKey?: string;
// The name to annotate the selector with
label?: string;
+
+ onChange(value: number, powerLevelKey: K extends undefined ? void : K): void;
+
+ // Optional key to pass as the second argument to `onChange`
+ powerLevelKey: K extends undefined ? void : K;
}
interface IState {
@@ -54,13 +55,13 @@ interface IState {
custom?: boolean;
}
-export default class PowerSelector extends React.Component {
- public static defaultProps: Partial = {
+export default class PowerSelector extends React.Component, IState> {
+ public static defaultProps: Partial> = {
maxValue: Infinity,
usersDefault: 0,
};
- public constructor(props: IProps) {
+ public constructor(props: Props) {
super(props);
this.state = {
@@ -77,7 +78,7 @@ export default class PowerSelector extends React.Component {
this.initStateFromProps();
}
- public componentDidUpdate(prevProps: Readonly): void {
+ public componentDidUpdate(prevProps: Readonly>): void {
if (objectHasDiff(this.props, prevProps)) {
this.initStateFromProps();
}
diff --git a/src/components/views/elements/QRCode.tsx b/src/components/views/elements/QRCode.tsx
index 292734d5ee..4ba8af2250 100644
--- a/src/components/views/elements/QRCode.tsx
+++ b/src/components/views/elements/QRCode.tsx
@@ -31,7 +31,7 @@ const defaultOptions: QRCodeToDataURLOptions = {
};
const QRCode: React.FC = ({ data, className, ...options }) => {
- const [dataUri, setUri] = React.useState(null);
+ const [dataUri, setUri] = React.useState(null);
React.useEffect(() => {
let cancelled = false;
toDataURL(data, { ...defaultOptions, ...options }).then((uri) => {
diff --git a/src/components/views/elements/ReplyChain.tsx b/src/components/views/elements/ReplyChain.tsx
index 30c4ed6cfb..9f80f4cf76 100644
--- a/src/components/views/elements/ReplyChain.tsx
+++ b/src/components/views/elements/ReplyChain.tsx
@@ -63,7 +63,7 @@ interface IState {
// The loaded events to be rendered as linear-replies
events: MatrixEvent[];
// The latest loaded event which has not yet been shown
- loadedEv: MatrixEvent;
+ loadedEv: MatrixEvent | null;
// Whether the component is still loading more events
loading: boolean;
// Whether as error was encountered fetching a replied to event.
@@ -145,7 +145,7 @@ export default class ReplyChain extends React.Component {
}
}
- private async getNextEvent(ev: MatrixEvent): Promise {
+ private async getNextEvent(ev: MatrixEvent): Promise {
try {
const inReplyToEventId = getParentEventId(ev);
return await this.getEvent(inReplyToEventId);
@@ -154,7 +154,7 @@ export default class ReplyChain extends React.Component {
}
}
- private async getEvent(eventId: string): Promise {
+ private async getEvent(eventId: string): Promise {
if (!eventId) return null;
const event = this.room.findEventById(eventId);
if (event) return event;
@@ -168,7 +168,7 @@ export default class ReplyChain extends React.Component {
// Return null as it is falsy and thus should be treated as an error (as the event cannot be resolved).
return null;
}
- return this.room.findEventById(eventId);
+ return this.room.findEventById(eventId) ?? null;
}
public canCollapse = (): boolean => {
@@ -182,7 +182,7 @@ export default class ReplyChain extends React.Component {
private onQuoteClick = async (event: ButtonEvent): Promise => {
const events = [this.state.loadedEv, ...this.state.events];
- let loadedEv = null;
+ let loadedEv: MatrixEvent | null = null;
if (events.length > 0) {
loadedEv = await this.getNextEvent(events[0]);
}
@@ -200,7 +200,7 @@ export default class ReplyChain extends React.Component {
}
public render(): React.ReactNode {
- let header = null;
+ let header: JSX.Element | undefined;
if (this.state.err) {
header = (
diff --git a/src/components/views/elements/Slider.tsx b/src/components/views/elements/Slider.tsx
index f6535679be..c8abeab620 100644
--- a/src/components/views/elements/Slider.tsx
+++ b/src/components/views/elements/Slider.tsx
@@ -81,7 +81,7 @@ export default class Slider extends React.Component {
/>
));
- let selection = null;
+ let selection: JSX.Element | undefined;
if (!this.props.disabled) {
const offset = this.offset(this.props.values, this.props.value);
diff --git a/src/components/views/elements/TruncatedList.tsx b/src/components/views/elements/TruncatedList.tsx
index c85a8658a6..01ad735a42 100644
--- a/src/components/views/elements/TruncatedList.tsx
+++ b/src/components/views/elements/TruncatedList.tsx
@@ -21,7 +21,7 @@ import { _t } from "../../../languageHandler";
interface IProps {
// The number of elements to show before truncating. If negative, no truncation is done.
- truncateAt?: number;
+ truncateAt: number;
// The className to apply to the wrapping div
className?: string;
// A function that returns the children to be rendered into the element.
@@ -34,7 +34,7 @@ interface IProps {
getChildCount?: () => number;
// A function which will be invoked when an overflow element is required.
// This will be inserted after the children.
- createOverflowElement?: (overflowCount: number, totalCount: number) => React.ReactNode;
+ createOverflowElement: (overflowCount: number, totalCount: number) => React.ReactNode;
children?: ReactNode;
}
@@ -71,8 +71,8 @@ export default class TruncatedList extends React.Component {
}
}
- public render(): React.ReactNode {
- let overflowNode = null;
+ public render(): ReactNode {
+ let overflowNode: ReactNode | undefined;
const totalChildren = this.getChildCount();
let upperBound = totalChildren;
diff --git a/src/components/views/right_panel/PinnedMessagesCard.tsx b/src/components/views/right_panel/PinnedMessagesCard.tsx
index f393ddd9a7..736ff03f2b 100644
--- a/src/components/views/right_panel/PinnedMessagesCard.tsx
+++ b/src/components/views/right_panel/PinnedMessagesCard.tsx
@@ -37,6 +37,7 @@ import RoomContext, { TimelineRenderingType } from "../../../contexts/RoomContex
import { ReadPinsEventId } from "./types";
import Heading from "../typography/Heading";
import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks";
+import { filterBoolean } from "../../../utils/arrays";
interface IProps {
room: Room;
@@ -44,7 +45,7 @@ interface IProps {
onClose(): void;
}
-export const usePinnedEvents = (room: Room): string[] => {
+export const usePinnedEvents = (room?: Room): string[] => {
const [pinnedEvents, setPinnedEvents] = useState([]);
const update = useCallback(
@@ -173,8 +174,7 @@ const PinnedMessagesCard: React.FC = ({ room, onClose, permalinkCreator
};
// show them in reverse, with latest pinned at the top
- content = pinnedEvents
- .filter(Boolean)
+ content = filterBoolean(pinnedEvents)
.reverse()
.map((ev) => (
= ({ room, permalinkCreator, onClose })
const memberCount = useRoomMemberCount(room);
const pinningEnabled = useFeatureEnabled("feature_pinning");
- const pinCount = usePinnedEvents(pinningEnabled && room)?.length;
+ const pinCount = usePinnedEvents(pinningEnabled ? room : undefined)?.length;
const isPollHistoryEnabled = useFeatureEnabled("feature_poll_history");
diff --git a/src/components/views/rooms/E2EIcon.tsx b/src/components/views/rooms/E2EIcon.tsx
index dd4960339c..b93f87abc5 100644
--- a/src/components/views/rooms/E2EIcon.tsx
+++ b/src/components/views/rooms/E2EIcon.tsx
@@ -44,7 +44,7 @@ const crossSigningRoomTitles: { [key in E2EState]?: string } = {
interface IProps {
isUser?: boolean;
- status?: E2EState | E2EStatus;
+ status: E2EState | E2EStatus;
className?: string;
size?: number;
onClick?: () => void;
@@ -76,7 +76,7 @@ const E2EIcon: React.FC = ({
className,
);
- let e2eTitle;
+ let e2eTitle: string | undefined;
if (isUser) {
e2eTitle = crossSigningUserTitles[status];
} else {
diff --git a/src/components/views/rooms/EntityTile.tsx b/src/components/views/rooms/EntityTile.tsx
index 065bc04008..14d4bbc45a 100644
--- a/src/components/views/rooms/EntityTile.tsx
+++ b/src/components/views/rooms/EntityTile.tsx
@@ -43,7 +43,7 @@ const PRESENCE_CLASS: Record = {
unavailable: "mx_EntityTile_unavailable",
};
-function presenceClassForMember(presenceState: PresenceState, lastActiveAgo: number, showPresence: boolean): string {
+function presenceClassForMember(presenceState?: PresenceState, lastActiveAgo?: number, showPresence?: boolean): string {
if (showPresence === false) {
return "mx_EntityTile_online_beenactive";
}
@@ -74,7 +74,7 @@ interface IProps {
presenceLastTs?: number;
presenceCurrentlyActive?: boolean;
showInviteButton?: boolean;
- onClick?(): void;
+ onClick(): void;
suppressOnHover?: boolean;
showPresence?: boolean;
subtextLabel?: string;
@@ -108,7 +108,7 @@ export default class EntityTile extends React.PureComponent {
public render(): React.ReactNode {
const mainClassNames: Record = {
mx_EntityTile: true,
- mx_EntityTile_noHover: this.props.suppressOnHover,
+ mx_EntityTile_noHover: !!this.props.suppressOnHover,
};
if (this.props.className) mainClassNames[this.props.className] = true;
@@ -127,7 +127,7 @@ export default class EntityTile extends React.PureComponent {
? Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)
: -1;
- let presenceLabel = null;
+ let presenceLabel: JSX.Element | undefined;
if (this.props.showPresence) {
presenceLabel = (
{
// Return duration as a string using appropriate time units
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
- private getDuration(time: number): string {
+ private getDuration(time: number): string | undefined {
if (!time) return;
const t = Math.round(time / 1000);
const s = t % 60;
@@ -61,11 +61,11 @@ export default class PresenceLabel extends React.Component {
return _t("%(duration)sd", { duration: d });
}
- private getPrettyPresence(presence: string, activeAgo: number, currentlyActive: boolean): string {
+ private getPrettyPresence(presence?: string, activeAgo?: number, currentlyActive?: boolean): string {
// for busy presence, we ignore the 'currentlyActive' flag: they're busy whether
// they're active or not. It can be set while the user is active in which case
// the 'active ago' ends up being 0.
- if (BUSY_PRESENCE_NAME.matches(presence)) return _t("Busy");
+ if (presence && BUSY_PRESENCE_NAME.matches(presence)) return _t("Busy");
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
const duration = this.getDuration(activeAgo);
diff --git a/src/components/views/settings/account/PhoneNumbers.tsx b/src/components/views/settings/account/PhoneNumbers.tsx
index f2233c5e6b..305a198bcc 100644
--- a/src/components/views/settings/account/PhoneNumbers.tsx
+++ b/src/components/views/settings/account/PhoneNumbers.tsx
@@ -129,9 +129,9 @@ interface IProps {
interface IState {
verifying: boolean;
- verifyError: string;
+ verifyError: string | null;
verifyMsisdn: string;
- addTask: AddThreepid;
+ addTask: AddThreepid | null;
continueDisabled: boolean;
phoneCountry: string;
newPhoneNumber: string;
@@ -205,7 +205,7 @@ export default class PhoneNumbers extends React.Component {
const token = this.state.newPhoneNumberCode;
const address = this.state.verifyMsisdn;
this.state.addTask
- .haveMsisdnToken(token)
+ ?.haveMsisdnToken(token)
.then(([finished]) => {
let newPhoneNumber = this.state.newPhoneNumber;
if (finished) {
diff --git a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
index db39176257..6e455e5131 100644
--- a/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
+++ b/src/components/views/settings/tabs/room/RolesRoomSettingsTab.tsx
@@ -21,6 +21,7 @@ import { RoomState, RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
import { logger } from "matrix-js-sdk/src/logger";
import { throttle, get } from "lodash";
import { compare } from "matrix-js-sdk/src/utils";
+import { IContent } from "matrix-js-sdk/src/models/event";
import { _t, _td } from "../../../../../languageHandler";
import { MatrixClientPeg } from "../../../../../MatrixClientPeg";
@@ -171,8 +172,8 @@ export default class RolesRoomSettingsTab extends React.Component {
private onPowerLevelsChanged = (value: number, powerLevelKey: string): void => {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.roomId);
- const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
- let plContent = plEvent ? plEvent.getContent() || {} : {};
+ const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
+ let plContent = plEvent?.getContent() ?? {};
// Clone the power levels just in case
plContent = Object.assign({}, plContent);
@@ -185,7 +186,7 @@ export default class RolesRoomSettingsTab extends React.Component {
plContent["events"][powerLevelKey.slice(eventsLevelPrefix.length)] = value;
} else {
const keyPath = powerLevelKey.split(".");
- let parentObj;
+ let parentObj: IContent | undefined;
let currentObj = plContent;
for (const key of keyPath) {
if (!currentObj[key]) {
@@ -213,8 +214,8 @@ export default class RolesRoomSettingsTab extends React.Component {
private onUserPowerLevelChanged = (value: number, powerLevelKey: string): void => {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.roomId);
- const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
- let plContent = plEvent ? plEvent.getContent() || {} : {};
+ const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
+ let plContent = plEvent?.getContent() ?? {};
// Clone the power levels just in case
plContent = Object.assign({}, plContent);
diff --git a/src/stores/WidgetStore.ts b/src/stores/WidgetStore.ts
index 849917bb8b..35668b4812 100644
--- a/src/stores/WidgetStore.ts
+++ b/src/stores/WidgetStore.ts
@@ -113,7 +113,7 @@ export default class WidgetStore extends AsyncStoreWithClient {
});
}
- private loadRoomWidgets(room: Room): void {
+ private loadRoomWidgets(room: Room | null): void {
if (!room) return;
const roomInfo = this.roomMap.get(room.roomId) || {};
roomInfo.widgets = [];
diff --git a/src/utils/localRoom/isLocalRoom.ts b/src/utils/localRoom/isLocalRoom.ts
index f2d7e3acfd..dffebd9777 100644
--- a/src/utils/localRoom/isLocalRoom.ts
+++ b/src/utils/localRoom/isLocalRoom.ts
@@ -18,7 +18,7 @@ import { Room } from "matrix-js-sdk/src/matrix";
import { LocalRoom, LOCAL_ROOM_ID_PREFIX } from "../../models/LocalRoom";
-export function isLocalRoom(roomOrID: Room | string): boolean {
+export function isLocalRoom(roomOrID?: Room | string): boolean {
if (typeof roomOrID === "string") {
return roomOrID.startsWith(LOCAL_ROOM_ID_PREFIX);
}
diff --git a/test/components/structures/TabbedView-test.tsx b/test/components/structures/TabbedView-test.tsx
index 520d406e48..922c7ccc3f 100644
--- a/test/components/structures/TabbedView-test.tsx
+++ b/test/components/structures/TabbedView-test.tsx
@@ -18,6 +18,7 @@ import React from "react";
import { act, fireEvent, render } from "@testing-library/react";
import TabbedView, { Tab, TabLocation } from "../../../src/components/structures/TabbedView";
+import { NonEmptyArray } from "../../../src/@types/common";
describe(" ", () => {
const generalTab = new Tab("GENERAL", "General", "general", general
);
@@ -25,7 +26,7 @@ describe(" ", () => {
const securityTab = new Tab("SECURITY", "Security", "security", security
);
const defaultProps = {
tabLocation: TabLocation.LEFT,
- tabs: [generalTab, labsTab, securityTab],
+ tabs: [generalTab, labsTab, securityTab] as NonEmptyArray,
};
const getComponent = (props = {}): React.ReactElement => ;
@@ -58,11 +59,6 @@ describe(" ", () => {
expect(getActiveTabBody(container)?.textContent).toEqual("security");
});
- it("renders without error when there are no tabs", () => {
- const { container } = render(getComponent({ tabs: [] }));
- expect(container).toMatchSnapshot();
- });
-
it("sets active tab on tab click", () => {
const { container, getByTestId } = render(getComponent());
diff --git a/test/components/structures/__snapshots__/TabbedView-test.tsx.snap b/test/components/structures/__snapshots__/TabbedView-test.tsx.snap
index bee195c1a0..77ead236a3 100644
--- a/test/components/structures/__snapshots__/TabbedView-test.tsx.snap
+++ b/test/components/structures/__snapshots__/TabbedView-test.tsx.snap
@@ -69,15 +69,3 @@ exports[` renders tabs 1`] = `