Conform more code to strict null checking (#10169)

* Conform more code to strict null checking

* delint

* Iterate

* delint

* Fix bad test
This commit is contained in:
Michael Telatynski 2023-02-16 09:38:44 +00:00 committed by GitHub
parent 5123d7e641
commit e8b92b308b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
85 changed files with 283 additions and 287 deletions

View file

@ -28,10 +28,10 @@ import { SettingLevel } from "../../../settings/SettingLevel";
interface IProps {
userId?: string;
displayName: string;
avatarUrl: string;
displayName?: string;
avatarUrl?: string;
messagePreviewText: string;
onLayoutChanged?: (layout: Layout) => void;
onLayoutChanged: (layout: Layout) => void;
}
interface IState {

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { IAnnotatedPushRule, IPusher, PushRuleAction, PushRuleKind, RuleId } from "matrix-js-sdk/src/@types/PushRules";
import { IThreepid, ThreepidMedium } from "matrix-js-sdk/src/@types/threepids";
import { logger } from "matrix-js-sdk/src/logger";
@ -152,7 +152,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
// the master rule is *enabled* it means all other rules are *disabled* (or
// inhibited). Conversely, when the master rule is *disabled* then all other rules
// are *enabled* (or operate fine).
return this.state.masterPushRule?.enabled;
return !!this.state.masterPushRule?.enabled;
}
public componentDidMount(): void {
@ -622,12 +622,12 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
);
}
private renderCategory(category: RuleClass): JSX.Element {
private renderCategory(category: RuleClass): ReactNode {
if (category !== RuleClass.VectorOther && this.isInhibited) {
return null; // nothing to show for the section
}
let clearNotifsButton: JSX.Element;
let clearNotifsButton: JSX.Element | undefined;
if (
category === RuleClass.VectorOther &&
MatrixClientPeg.get()
@ -660,7 +660,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
return null;
}
let keywordComposer: JSX.Element;
let keywordComposer: JSX.Element | undefined;
if (category === RuleClass.VectorMentions) {
keywordComposer = (
<TagComposer
@ -691,7 +691,7 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
/>
);
const fieldsetRows = this.state.vectorPushRules[category].map((r) => (
const fieldsetRows = this.state.vectorPushRules[category]?.map((r) => (
<fieldset
key={category + r.ruleId}
data-testid={category + r.ruleId}
@ -736,10 +736,10 @@ export default class Notifications extends React.PureComponent<IProps, IState> {
);
}
private renderTargets(): JSX.Element {
private renderTargets(): ReactNode {
if (this.isInhibited) return null; // no targets if there's no notifications
const rows = this.state.pushers.map((p) => (
const rows = this.state.pushers?.map((p) => (
<tr key={p.kind + p.pushkey}>
<td>{p.app_display_name}</td>
<td>{p.device_display_name}</td>

View file

@ -34,11 +34,11 @@ import PosthogTrackers from "../../../PosthogTrackers";
interface IState {
userId?: string;
originalDisplayName?: string;
displayName?: string;
originalAvatarUrl?: string;
originalDisplayName: string;
displayName: string;
originalAvatarUrl: string | null;
avatarUrl?: string | ArrayBuffer;
avatarFile?: File;
avatarFile?: File | null;
enableProfileSave?: boolean;
}
@ -52,25 +52,25 @@ export default class ProfileSettings extends React.Component<{}, IState> {
let avatarUrl = OwnProfileStore.instance.avatarMxc;
if (avatarUrl) avatarUrl = mediaFromMxc(avatarUrl).getSquareThumbnailHttp(96);
this.state = {
userId: client.getUserId(),
originalDisplayName: OwnProfileStore.instance.displayName,
displayName: OwnProfileStore.instance.displayName,
userId: client.getUserId()!,
originalDisplayName: OwnProfileStore.instance.displayName ?? "",
displayName: OwnProfileStore.instance.displayName ?? "",
originalAvatarUrl: avatarUrl,
avatarUrl: avatarUrl,
avatarUrl: avatarUrl ?? undefined,
avatarFile: null,
enableProfileSave: false,
};
}
private uploadAvatar = (): void => {
this.avatarUpload.current.click();
this.avatarUpload.current?.click();
};
private removeAvatar = (): void => {
// clear file upload field so same file can be selected
this.avatarUpload.current.value = "";
this.setState({
avatarUrl: null,
avatarUrl: undefined,
avatarFile: null,
enableProfileSave: true,
});
@ -84,7 +84,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
this.setState({
enableProfileSave: false,
displayName: this.state.originalDisplayName,
avatarUrl: this.state.originalAvatarUrl,
avatarUrl: this.state.originalAvatarUrl ?? undefined,
avatarFile: null,
});
};
@ -97,7 +97,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
this.setState({ enableProfileSave: false });
const client = MatrixClientPeg.get();
const newState: IState = {};
const newState: Partial<IState> = {};
const displayName = this.state.displayName.trim();
try {
@ -114,7 +114,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
);
const { content_uri: uri } = await client.uploadContent(this.state.avatarFile);
await client.setAvatarUrl(uri);
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96);
newState.avatarUrl = mediaFromMxc(uri).getSquareThumbnailHttp(96) ?? undefined;
newState.originalAvatarUrl = newState.avatarUrl;
newState.avatarFile = null;
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
@ -128,7 +128,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
});
}
this.setState(newState);
this.setState<any>(newState);
};
private onDisplayNameChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
@ -141,7 +141,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
private onAvatarChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
if (!e.target.files || !e.target.files.length) {
this.setState({
avatarUrl: this.state.originalAvatarUrl,
avatarUrl: this.state.originalAvatarUrl ?? undefined,
avatarFile: null,
enableProfileSave: false,
});
@ -152,7 +152,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
const reader = new FileReader();
reader.onload = (ev) => {
this.setState({
avatarUrl: ev.target.result,
avatarUrl: ev.target?.result,
avatarFile: file,
enableProfileSave: true,
});
@ -162,7 +162,7 @@ export default class ProfileSettings extends React.Component<{}, IState> {
public render(): React.ReactNode {
const hostingSignupLink = getHostingLink("user-settings");
let hostingSignup = null;
let hostingSignup: JSX.Element | undefined;
if (hostingSignupLink) {
hostingSignup = (
<span>

View file

@ -27,7 +27,7 @@ import ToggleSwitch from "../elements/ToggleSwitch";
interface IProps {}
interface IState {
currentManager: IntegrationManagerInstance;
currentManager: IntegrationManagerInstance | null;
provisioningEnabled: boolean;
}

View file

@ -162,7 +162,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
this.setState({ customThemeUrl: e.target.value });
};
private renderHighContrastCheckbox(): React.ReactElement<HTMLDivElement> {
private renderHighContrastCheckbox(): React.ReactElement<HTMLDivElement> | undefined {
if (
!this.state.useSystemTheme &&
(findHighContrastTheme(this.state.theme) || isHighContrastTheme(this.state.theme))
@ -181,7 +181,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
}
private highContrastThemeChanged(checked: boolean): void {
let newTheme: string;
let newTheme: string | undefined;
if (checked) {
newTheme = findHighContrastTheme(this.state.theme);
} else {
@ -194,7 +194,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
public render(): React.ReactElement<HTMLDivElement> {
const themeWatcher = new ThemeWatcher();
let systemThemeSection: JSX.Element;
let systemThemeSection: JSX.Element | undefined;
if (themeWatcher.isSystemThemeSupported()) {
systemThemeSection = (
<div>
@ -208,9 +208,9 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
);
}
let customThemeForm: JSX.Element;
let customThemeForm: JSX.Element | undefined;
if (SettingsStore.getValue("feature_custom_themes")) {
let messageElement = null;
let messageElement: JSX.Element | undefined;
if (this.state.customThemeMessage.text) {
if (this.state.customThemeMessage.isError) {
messageElement = <div className="text-error">{this.state.customThemeMessage.text}</div>;
@ -268,7 +268,7 @@ export default class ThemeChoicePanel extends React.Component<IProps, IState> {
);
}
public apparentSelectedThemeId(): string {
public apparentSelectedThemeId(): string | undefined {
if (this.state.useSystemTheme) {
return undefined;
}

View file

@ -27,7 +27,7 @@ import AccessibleButton from "../../../components/views/elements/AccessibleButto
import { CheckUpdatesPayload } from "../../../dispatcher/payloads/CheckUpdatesPayload";
function installUpdate(): void {
PlatformPeg.get().installUpdate();
PlatformPeg.get()?.installUpdate();
}
function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNode {
@ -58,11 +58,11 @@ function getStatusText(status: UpdateCheckStatus, errorDetail?: string): ReactNo
const doneStatuses = [UpdateCheckStatus.Ready, UpdateCheckStatus.Error, UpdateCheckStatus.NotAvailable];
const UpdateCheckButton: React.FC = () => {
const [state, setState] = useState<CheckUpdatesPayload>(null);
const [state, setState] = useState<CheckUpdatesPayload | null>(null);
const onCheckForUpdateClick = (): void => {
setState(null);
PlatformPeg.get().startUpdateCheck();
PlatformPeg.get()?.startUpdateCheck();
};
useDispatcher(dis, ({ action, ...params }) => {
@ -71,9 +71,9 @@ const UpdateCheckButton: React.FC = () => {
}
});
const busy = state && !doneStatuses.includes(state.status);
const busy = !!state && !doneStatuses.includes(state.status);
let suffix;
let suffix: JSX.Element | undefined;
if (state) {
suffix = (
<span className="mx_UpdateCheckButton_summary">

View file

@ -31,14 +31,14 @@ import { ExtendedDevice } from "./types";
interface Props {
device: ExtendedDevice;
pusher?: IPusher | undefined;
localNotificationSettings?: LocalNotificationSettings | undefined;
pusher?: IPusher;
localNotificationSettings?: LocalNotificationSettings;
isSigningOut: boolean;
onVerifyDevice?: () => void;
onSignOutDevice: () => void;
saveDeviceName: (deviceName: string) => Promise<void>;
setPushNotifications?: (deviceId: string, enabled: boolean) => Promise<void> | undefined;
supportsMSC3881?: boolean | undefined;
setPushNotifications?: (deviceId: string, enabled: boolean) => Promise<void>;
supportsMSC3881?: boolean;
className?: string;
isCurrentDevice?: boolean;
}

View file

@ -23,7 +23,7 @@ import SettingsSubsection from "../shared/SettingsSubsection";
interface IProps {
onShowQr: () => void;
versions: IServerVersions;
versions?: IServerVersions;
}
export default class LoginWithQRSection extends React.Component<IProps> {

View file

@ -40,6 +40,7 @@ interface IRecommendedVersion {
}
interface IState {
// This is eventually set to the value of room.getRecommendedVersion()
upgradeRecommendation?: IRecommendedVersion;
oldRoomId?: string;
oldEventId?: string;
@ -52,14 +53,11 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
const msc3946ProcessDynamicPredecessor = SettingsStore.getValue("feature_dynamic_room_predecessors");
this.state = {
// This is eventually set to the value of room.getRecommendedVersion()
upgradeRecommendation: null,
};
this.state = {};
// we handle lack of this object gracefully later, so don't worry about it failing here.
const room = MatrixClientPeg.get().getRoom(this.props.roomId);
room.getRecommendedVersion().then((v) => {
room?.getRecommendedVersion().then((v) => {
const tombstone = room.currentState.getStateEvents(EventType.RoomTombstone, "");
const additionalStateChanges: Partial<IState> = {};
@ -99,11 +97,10 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
public render(): React.ReactNode {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.roomId);
const isSpace = room.isSpaceRoom();
const isSpace = room?.isSpaceRoom();
let unfederatableSection;
const createEvent = room.currentState.getStateEvents(EventType.RoomCreate, "");
if (createEvent && createEvent.getContent()["m.federate"] === false) {
let unfederatableSection: JSX.Element | undefined;
if (room?.currentState.getStateEvents(EventType.RoomCreate, "")?.getContent()["m.federate"] === false) {
unfederatableSection = <div>{_t("This room is not accessible by remote Matrix servers")}</div>;
}
@ -132,13 +129,13 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
);
}
let oldRoomLink;
let oldRoomLink: JSX.Element | undefined;
if (this.state.oldRoomId) {
let copy: string;
if (isSpace) {
copy = _t("View older version of %(spaceName)s.", { spaceName: room.name });
copy = _t("View older version of %(spaceName)s.", { spaceName: room?.name ?? this.state.oldRoomId });
} else {
copy = _t("View older messages in %(roomName)s.", { roomName: room.name });
copy = _t("View older messages in %(roomName)s.", { roomName: room?.name ?? this.state.oldRoomId });
}
oldRoomLink = (
@ -165,7 +162,7 @@ export default class AdvancedRoomSettingsTab extends React.Component<IProps, ISt
<span className="mx_SettingsTab_subheading">{_t("Room version")}</span>
<div>
<span>{_t("Room version:")}</span>&nbsp;
{room.getVersion()}
{room?.getVersion()}
</div>
{oldRoomLink}
{roomUpgradeButton}

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
@ -34,17 +34,16 @@ interface IProps {
}
export default class BridgeSettingsTab extends React.Component<IProps> {
private renderBridgeCard(event: MatrixEvent, room: Room): JSX.Element {
private renderBridgeCard(event: MatrixEvent, room: Room | null): ReactNode {
const content = event.getContent();
if (!content || !content.channel || !content.protocol) {
return null;
}
if (!room || !content?.channel || !content.protocol) return null;
return <BridgeTile key={event.getId()} room={room} ev={event} />;
}
public static getBridgeStateEvents(roomId: string): MatrixEvent[] {
const client = MatrixClientPeg.get();
const roomState = client.getRoom(roomId).currentState;
const roomState = client.getRoom(roomId)?.currentState;
if (!roomState) return [];
return BRIDGE_EVENT_TYPES.map((typeName) => roomState.getStateEvents(typeName)).flat(1);
}

View file

@ -61,15 +61,14 @@ export default class GeneralRoomSettingsTab extends React.Component<IProps, ISta
const room = client.getRoom(this.props.roomId);
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", "");
const canSetCanonical = room?.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
const canonicalAliasEv = room?.currentState.getStateEvents("m.room.canonical_alias", "") ?? undefined;
const urlPreviewSettings = SettingsStore.getValue(UIFeature.URLPreviews) ? (
<UrlPreviewSettings room={room} />
) : null;
const urlPreviewSettings =
room && SettingsStore.getValue(UIFeature.URLPreviews) ? <UrlPreviewSettings room={room} /> : null;
let leaveSection;
if (room.getMyMembership() === "join") {
if (room?.getMyMembership() === "join") {
leaveSection = (
<>
<span className="mx_SettingsTab_subheading">{_t("Leave room")}</span>

View file

@ -40,7 +40,7 @@ interface IProps {
interface IState {
currentSound: string;
uploadedFile: File;
uploadedFile: File | null;
}
export default class NotificationsSettingsTab extends React.Component<IProps, IState> {
@ -71,7 +71,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
e.stopPropagation();
e.preventDefault();
this.soundUpload.current.click();
this.soundUpload.current?.click();
};
private onSoundUploadChanged = (e: React.ChangeEvent<HTMLInputElement>): void => {
@ -156,7 +156,7 @@ export default class NotificationsSettingsTab extends React.Component<IProps, IS
};
public render(): React.ReactNode {
let currentUploadedFile = null;
let currentUploadedFile: JSX.Element | undefined;
if (this.state.uploadedFile) {
currentUploadedFile = (
<div>

View file

@ -239,13 +239,13 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
public render(): React.ReactNode {
const client = MatrixClientPeg.get();
const room = client.getRoom(this.props.roomId);
const isSpaceRoom = room.isSpaceRoom();
const isSpaceRoom = room?.isSpaceRoom();
const plEvent = room.currentState.getStateEvents(EventType.RoomPowerLevels, "");
const plEvent = room?.currentState.getStateEvents(EventType.RoomPowerLevels, "");
const plContent = plEvent ? plEvent.getContent() || {} : {};
const canChangeLevels = room.currentState.mayClientSendStateEvent(EventType.RoomPowerLevels, client);
const canChangeLevels = room?.currentState.mayClientSendStateEvent(EventType.RoomPowerLevels, client);
const plEventsToLabels: Record<EventType | string, string> = {
const plEventsToLabels: Record<EventType | string, string | null> = {
// These will be translated for us later.
[EventType.RoomAvatar]: isSpaceRoom ? _td("Change space avatar") : _td("Change room avatar"),
[EventType.RoomName]: isSpaceRoom ? _td("Change space name") : _td("Change room name"),
@ -322,7 +322,7 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
powerLevelDescriptors.users_default.defaultValue,
);
let currentUserLevel = userLevels[client.getUserId()];
let currentUserLevel = userLevels[client.getUserId()!];
if (currentUserLevel === undefined) {
currentUserLevel = defaultUserLevel;
}
@ -391,16 +391,16 @@ export default class RolesRoomSettingsTab extends React.Component<IProps> {
}
}
const banned = room.getMembersWithMembership("ban");
let bannedUsersSection;
if (banned.length) {
const banned = room?.getMembersWithMembership("ban");
let bannedUsersSection: JSX.Element | undefined;
if (banned?.length) {
const canBanUsers = currentUserLevel >= banLevel;
bannedUsersSection = (
<SettingsFieldset legend={_t("Banned users")}>
<ul>
{banned.map((member) => {
const banEvent = member.events.member.getContent();
const sender = room.getMember(member.events.member.getSender());
const banEvent = member.events.member?.getContent();
const sender = room?.getMember(member.events.member.getSender());
let bannedBy = member.events.member.getSender(); // start by falling back to mxid
if (sender) bannedBy = sender.name;
return (

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { GuestAccess, HistoryVisibility, JoinRule } from "matrix-js-sdk/src/@types/partials";
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { RoomStateEvent } from "matrix-js-sdk/src/models/room-state";
@ -61,16 +61,16 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
public constructor(props: IProps, context: React.ContextType<typeof MatrixClientContext>) {
super(props, context);
const state = context.getRoom(this.props.roomId).currentState;
const state = context.getRoom(this.props.roomId)?.currentState;
this.state = {
guestAccess: this.pullContentPropertyFromEvent<GuestAccess>(
state.getStateEvents(EventType.RoomGuestAccess, ""),
state?.getStateEvents(EventType.RoomGuestAccess, ""),
"guest_access",
GuestAccess.Forbidden,
),
history: this.pullContentPropertyFromEvent<HistoryVisibility>(
state.getStateEvents(EventType.RoomHistoryVisibility, ""),
state?.getStateEvents(EventType.RoomHistoryVisibility, ""),
"history_visibility",
HistoryVisibility.Shared,
),
@ -85,7 +85,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
this.hasAliases().then((hasAliases) => this.setState({ hasAliases }));
}
private pullContentPropertyFromEvent<T>(event: MatrixEvent, key: string, defaultValue: T): T {
private pullContentPropertyFromEvent<T>(event: MatrixEvent | null | undefined, key: string, defaultValue: T): T {
return event?.getContent()[key] || defaultValue;
}
@ -117,7 +117,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
"You'll get none of the benefits of encryption, and you won't be able to turn it " +
"off later. Encrypting messages in a public room will make receiving and sending " +
"messages slower.",
null,
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
</p>
@ -126,7 +126,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
{_t(
"To avoid these issues, create a <a>new encrypted room</a> for " +
"the conversation you plan to have.",
null,
undefined,
{
a: (sub) => (
<AccessibleButton
@ -236,7 +236,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
};
private updateBlacklistDevicesFlag = (checked: boolean): void => {
this.context.getRoom(this.props.roomId).setBlacklistUnverifiedDevices(checked);
this.context.getRoom(this.props.roomId)?.setBlacklistUnverifiedDevices(checked);
};
private async hasAliases(): Promise<boolean> {
@ -250,8 +250,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
const client = this.context;
const room = client.getRoom(this.props.roomId);
let aliasWarning = null;
if (room.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
let aliasWarning: JSX.Element | undefined;
if (room?.getJoinRule() === JoinRule.Public && !this.state.hasAliases) {
aliasWarning = (
<div className="mx_SecurityRoomSettingsTab_warning">
<WarningIcon width={15} height={15} />
@ -297,7 +297,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
"It will mean anyone can find and join the room, so anyone can read messages. " +
"You'll get none of the benefits of encryption. Encrypting messages in a public " +
"room will make receiving and sending messages slower.",
null,
undefined,
{ b: (sub) => <b>{sub}</b> },
)}{" "}
</p>
@ -306,7 +306,7 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
{_t(
"To avoid these issues, create a <a>new public room</a> for the conversation " +
"you plan to have.",
null,
undefined,
{
a: (sub) => (
<AccessibleButton
@ -335,15 +335,15 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
return true;
};
private renderHistory(): JSX.Element {
private renderHistory(): ReactNode {
if (!SettingsStore.getValue(UIFeature.RoomHistorySettings)) {
return null;
}
const client = this.context;
const history = this.state.history;
const state = client.getRoom(this.props.roomId).currentState;
const canChangeHistory = state.mayClientSendStateEvent(EventType.RoomHistoryVisibility, client);
const state = client.getRoom(this.props.roomId)?.currentState;
const canChangeHistory = state?.mayClientSendStateEvent(EventType.RoomHistoryVisibility, client);
const options = [
{
@ -393,8 +393,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
private renderAdvanced(): JSX.Element {
const client = this.context;
const guestAccess = this.state.guestAccess;
const state = client.getRoom(this.props.roomId).currentState;
const canSetGuestAccess = state.mayClientSendStateEvent(EventType.RoomGuestAccess, client);
const state = client.getRoom(this.props.roomId)?.currentState;
const canSetGuestAccess = state?.mayClientSendStateEvent(EventType.RoomGuestAccess, client);
return (
<>
@ -418,10 +418,10 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
const client = this.context;
const room = client.getRoom(this.props.roomId);
const isEncrypted = this.state.encrypted;
const hasEncryptionPermission = room.currentState.mayClientSendStateEvent(EventType.RoomEncryption, client);
const hasEncryptionPermission = room?.currentState.mayClientSendStateEvent(EventType.RoomEncryption, client);
const canEnableEncryption = !isEncrypted && hasEncryptionPermission;
let encryptionSettings = null;
let encryptionSettings: JSX.Element | undefined;
if (isEncrypted && SettingsStore.isEnabled("blacklistUnverifiedDevices")) {
encryptionSettings = (
<SettingsFlag
@ -435,8 +435,8 @@ export default class SecurityRoomSettingsTab extends React.Component<IProps, ISt
const historySection = this.renderHistory();
let advanced;
if (room.getJoinRule() === JoinRule.Public) {
let advanced: JSX.Element | undefined;
if (room?.getJoinRule() === JoinRule.Public) {
advanced = (
<div className="mx_SettingsTab_section">
<AccessibleButton

View file

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React, { ChangeEvent } from "react";
import React, { ChangeEvent, ReactNode } from "react";
import { _t } from "../../../../../languageHandler";
import SdkConfig from "../../../../../SdkConfig";
@ -41,8 +41,8 @@ interface IState {
layout: Layout;
// User profile data for the message preview
userId?: string;
displayName: string;
avatarUrl: string;
displayName?: string;
avatarUrl?: string;
}
export default class AppearanceUserSettingsTab extends React.Component<IProps, IState> {
@ -58,16 +58,13 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
systemFont: SettingsStore.getValue("systemFont"),
showAdvanced: false,
layout: SettingsStore.getValue("layout"),
userId: null,
displayName: null,
avatarUrl: null,
};
}
public async componentDidMount(): Promise<void> {
// Fetch the current user profile for the message preview
const client = MatrixClientPeg.get();
const userId = client.getUserId();
const userId = client.getUserId()!;
const profileInfo = await client.getProfileInfo(userId);
if (this.unmounted) return;
@ -86,7 +83,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
this.setState({ layout: layout });
};
private renderAdvancedSection(): JSX.Element {
private renderAdvancedSection(): ReactNode {
if (!SettingsStore.getValue(UIFeature.AdvancedSettings)) return null;
const brand = SdkConfig.get().brand;
@ -115,7 +112,7 @@ export default class AppearanceUserSettingsTab extends React.Component<IProps, I
/>
<Field
className="mx_AppearanceUserSettingsTab_systemFont"
label={SettingsStore.getDisplayName("systemFont")}
label={SettingsStore.getDisplayName("systemFont")!}
onChange={(value: ChangeEvent<HTMLInputElement>) => {
this.setState({
systemFont: value.target.value,

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { logger } from "matrix-js-sdk/src/logger";
import AccessibleButton from "../../../elements/AccessibleButton";
@ -37,7 +37,7 @@ interface IProps {
}
interface IState {
appVersion: string;
appVersion: string | null;
canUpdate: boolean;
}
@ -53,13 +53,13 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
public componentDidMount(): void {
PlatformPeg.get()
.getAppVersion()
?.getAppVersion()
.then((ver) => this.setState({ appVersion: ver }))
.catch((e) => {
logger.error("Error getting vector version: ", e);
});
PlatformPeg.get()
.canSelfUpdate()
?.canSelfUpdate()
.then((v) => this.setState({ canUpdate: v }))
.catch((e) => {
logger.error("Error getting self updatability: ", e);
@ -90,7 +90,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
MatrixClientPeg.get()
.store.deleteAllData()
.then(() => {
PlatformPeg.get().reload();
PlatformPeg.get()?.reload();
});
};
@ -106,11 +106,11 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
});
};
private renderLegal(): JSX.Element {
private renderLegal(): ReactNode {
const tocLinks = SdkConfig.get().terms_and_conditions_links;
if (!tocLinks) return null;
const legalLinks = [];
const legalLinks: JSX.Element[] = [];
for (const tocEntry of tocLinks) {
legalLinks.push(
<div key={tocEntry.url}>
@ -248,7 +248,7 @@ export default class HelpUserSettingsTab extends React.Component<IProps, IState>
);
}
let updateButton = null;
let updateButton: JSX.Element | undefined;
if (this.state.canUpdate) {
updateButton = <UpdateCheckButton />;
}

View file

@ -105,7 +105,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
this.setState({ busy: true });
try {
const list = Mjolnir.sharedInstance().getPersonalList();
await list.unbanEntity(rule.kind, rule.entity);
await list!.unbanEntity(rule.kind, rule.entity);
} catch (e) {
logger.error(e);
@ -142,7 +142,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
const renderRules = (rules: ListRule[]): JSX.Element => {
if (rules.length === 0) return <i>{_t("None")}</i>;
const tiles = [];
const tiles: JSX.Element[] = [];
for (const rule of rules) {
tiles.push(
<li key={rule.kind + rule.entity}>
@ -173,7 +173,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
const rules = list ? [...list.userRules, ...list.serverRules] : [];
if (!list || rules.length <= 0) return <i>{_t("You have not ignored anyone.")}</i>;
const tiles = [];
const tiles: JSX.Element[] = [];
for (const rule of rules) {
tiles.push(
<li key={rule.entity} className="mx_MjolnirUserSettingsTab_listItem">
@ -205,7 +205,7 @@ export default class MjolnirUserSettingsTab extends React.Component<{}, IState>
});
if (!lists || lists.length <= 0) return <i>{_t("You are not subscribed to any lists")}</i>;
const tiles = [];
const tiles: JSX.Element[] = [];
for (const list of lists) {
const room = MatrixClientPeg.get().getRoom(list.roomId);
const name = room ? (

View file

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { sleep } from "matrix-js-sdk/src/utils";
import { Room, RoomEvent } from "matrix-js-sdk/src/models/room";
import { logger } from "matrix-js-sdk/src/logger";
@ -169,7 +169,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
return MatrixClientPeg.get()
.getRooms()
.filter((r) => {
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
return r.hasMembershipState(MatrixClientPeg.get().getUserId()!, "invite");
});
};
@ -247,7 +247,7 @@ export default class SecurityUserSettingsTab extends React.Component<IProps, ISt
);
}
private renderManageInvites(): JSX.Element {
private renderManageInvites(): ReactNode {
const { invitedRoomIds } = this.state;
if (invitedRoomIds.size === 0) {

View file

@ -15,7 +15,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
import React from "react";
import React, { ReactNode } from "react";
import { _t } from "../../../../../languageHandler";
import MediaDeviceHandler, { IMediaDevices, MediaDeviceKindEnum } from "../../../../../MediaDeviceHandler";
@ -28,10 +28,10 @@ import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
import { requestMediaPermissions } from "../../../../../utils/media/requestMediaPermissions";
interface IState {
mediaDevices: IMediaDevices;
[MediaDeviceKindEnum.AudioOutput]: string;
[MediaDeviceKindEnum.AudioInput]: string;
[MediaDeviceKindEnum.VideoInput]: string;
mediaDevices: IMediaDevices | null;
[MediaDeviceKindEnum.AudioOutput]: string | null;
[MediaDeviceKindEnum.AudioInput]: string | null;
[MediaDeviceKindEnum.VideoInput]: string | null;
audioAutoGainControl: boolean;
audioEchoCancellation: boolean;
audioNoiseSuppression: boolean;
@ -104,7 +104,7 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
});
}
private renderDropdown(kind: MediaDeviceKindEnum, label: string): JSX.Element {
private renderDropdown(kind: MediaDeviceKindEnum, label: string): ReactNode {
const devices = this.state.mediaDevices[kind].slice(0);
if (devices.length === 0) return null;
@ -121,11 +121,11 @@ export default class VoiceUserSettingsTab extends React.Component<{}, IState> {
);
}
public render(): React.ReactNode {
let requestButton = null;
let speakerDropdown = null;
let microphoneDropdown = null;
let webcamDropdown = null;
public render(): ReactNode {
let requestButton: ReactNode | undefined;
let speakerDropdown: ReactNode | undefined;
let microphoneDropdown: ReactNode | undefined;
let webcamDropdown: ReactNode | undefined;
if (!this.state.mediaDevices) {
requestButton = (
<div className="mx_VoiceUserSettingsTab_missingMediaPermissions">