Make more code conform to strict null checks (#10219
* Make more code conform to strict null checks * Fix types * Fix tests * Fix remaining test assertions * Iterate PR
This commit is contained in:
parent
4c79ecf141
commit
76b82b4b2b
130 changed files with 603 additions and 603 deletions
|
@ -46,7 +46,7 @@ interface IState {
|
|||
export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
||||
public static contextType = MatrixClientContext;
|
||||
private unmounted = false;
|
||||
private dispatcherRef: string = null;
|
||||
private dispatcherRef: string | null = null;
|
||||
|
||||
public constructor(props: IProps, context: typeof MatrixClientContext) {
|
||||
super(props, context);
|
||||
|
@ -64,7 +64,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
|||
let res: Response;
|
||||
|
||||
try {
|
||||
res = await fetch(this.props.url, { method: "GET" });
|
||||
res = await fetch(this.props.url!, { method: "GET" });
|
||||
} catch (err) {
|
||||
if (this.unmounted) return;
|
||||
logger.warn(`Error loading page: ${err}`);
|
||||
|
@ -84,7 +84,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
|||
|
||||
if (this.props.replaceMap) {
|
||||
Object.keys(this.props.replaceMap).forEach((key) => {
|
||||
body = body.split(key).join(this.props.replaceMap[key]);
|
||||
body = body.split(key).join(this.props.replaceMap![key]);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -123,8 +123,7 @@ export default class EmbeddedPage extends React.PureComponent<IProps, IState> {
|
|||
const client = this.context || MatrixClientPeg.get();
|
||||
const isGuest = client ? client.isGuest() : true;
|
||||
const className = this.props.className;
|
||||
const classes = classnames({
|
||||
[className]: true,
|
||||
const classes = classnames(className, {
|
||||
[`${className}_guest`]: isGuest,
|
||||
[`${className}_loggedIn`]: !!client,
|
||||
});
|
||||
|
|
|
@ -40,6 +40,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
|||
const onDragEnter = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
if (!ev.dataTransfer) return;
|
||||
|
||||
setState((state) => ({
|
||||
// We always increment the counter no matter the types, because dragging is
|
||||
|
@ -49,7 +50,8 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
|||
// https://docs.w3cub.com/dom/datatransfer/types
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/Recommended_drag_types#file
|
||||
dragging:
|
||||
ev.dataTransfer.types.includes("Files") || ev.dataTransfer.types.includes("application/x-moz-file")
|
||||
ev.dataTransfer!.types.includes("Files") ||
|
||||
ev.dataTransfer!.types.includes("application/x-moz-file")
|
||||
? true
|
||||
: state.dragging,
|
||||
}));
|
||||
|
@ -68,6 +70,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
|||
const onDragOver = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
if (!ev.dataTransfer) return;
|
||||
|
||||
ev.dataTransfer.dropEffect = "none";
|
||||
|
||||
|
@ -82,6 +85,7 @@ const FileDropTarget: React.FC<IProps> = ({ parent, onFileDrop }) => {
|
|||
const onDrop = (ev: DragEvent): void => {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
if (!ev.dataTransfer) return;
|
||||
onFileDrop(ev.dataTransfer);
|
||||
|
||||
setState((state) => ({
|
||||
|
|
|
@ -66,7 +66,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
|||
|
||||
private onRoomTimeline = (
|
||||
ev: MatrixEvent,
|
||||
room: Room | null,
|
||||
room: Room | undefined,
|
||||
toStartOfTimeline: boolean,
|
||||
removed: boolean,
|
||||
data: IRoomTimelineData,
|
||||
|
@ -78,7 +78,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
|||
client.decryptEventIfNeeded(ev);
|
||||
|
||||
if (ev.isBeingDecrypted()) {
|
||||
this.decryptingEvents.add(ev.getId());
|
||||
this.decryptingEvents.add(ev.getId()!);
|
||||
} else {
|
||||
this.addEncryptedLiveEvent(ev);
|
||||
}
|
||||
|
@ -86,7 +86,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
|||
|
||||
private onEventDecrypted = (ev: MatrixEvent, err?: any): void => {
|
||||
if (ev.getRoomId() !== this.props.roomId) return;
|
||||
const eventId = ev.getId();
|
||||
const eventId = ev.getId()!;
|
||||
|
||||
if (!this.decryptingEvents.delete(eventId)) return;
|
||||
if (err) return;
|
||||
|
@ -103,7 +103,7 @@ class FilePanel extends React.Component<IProps, IState> {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!this.state.timelineSet.eventIdToTimeline(ev.getId())) {
|
||||
if (!this.state.timelineSet.eventIdToTimeline(ev.getId()!)) {
|
||||
this.state.timelineSet.addEventToTimeline(ev, timeline, false);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,15 +56,15 @@ const getOwnProfile = (
|
|||
userId: string,
|
||||
): {
|
||||
displayName: string;
|
||||
avatarUrl: string;
|
||||
avatarUrl?: string;
|
||||
} => ({
|
||||
displayName: OwnProfileStore.instance.displayName || userId,
|
||||
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE),
|
||||
avatarUrl: OwnProfileStore.instance.getHttpAvatarUrl(AVATAR_SIZE) ?? undefined,
|
||||
});
|
||||
|
||||
const UserWelcomeTop: React.FC = () => {
|
||||
const cli = useContext(MatrixClientContext);
|
||||
const userId = cli.getUserId();
|
||||
const userId = cli.getUserId()!;
|
||||
const [ownProfile, setOwnProfile] = useState(getOwnProfile(userId));
|
||||
useEventEmitter(OwnProfileStore.instance, UPDATE_EVENT, () => {
|
||||
setOwnProfile(getOwnProfile(userId));
|
||||
|
|
|
@ -33,7 +33,7 @@ export const ERROR_USER_CANCELLED = new Error("User cancelled auth session");
|
|||
|
||||
type InteractiveAuthCallbackSuccess = (
|
||||
success: true,
|
||||
response: IAuthData,
|
||||
response?: IAuthData,
|
||||
extra?: { emailSid?: string; clientSecret?: string },
|
||||
) => void;
|
||||
type InteractiveAuthCallbackFailure = (success: false, response: IAuthData | Error) => void;
|
||||
|
@ -94,7 +94,7 @@ interface IState {
|
|||
|
||||
export default class InteractiveAuthComponent extends React.Component<IProps, IState> {
|
||||
private readonly authLogic: InteractiveAuth;
|
||||
private readonly intervalId: number = null;
|
||||
private readonly intervalId: number | null = null;
|
||||
private readonly stageComponent = createRef<IStageComponent>();
|
||||
|
||||
private unmounted = false;
|
||||
|
@ -103,10 +103,7 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
|
|||
super(props);
|
||||
|
||||
this.state = {
|
||||
authStage: null,
|
||||
busy: false,
|
||||
errorText: null,
|
||||
errorCode: null,
|
||||
submitButtonEnabled: false,
|
||||
};
|
||||
|
||||
|
@ -213,8 +210,8 @@ export default class InteractiveAuthComponent extends React.Component<IProps, IS
|
|||
if (busy) {
|
||||
this.setState({
|
||||
busy: true,
|
||||
errorText: null,
|
||||
errorCode: null,
|
||||
errorText: undefined,
|
||||
errorCode: undefined,
|
||||
});
|
||||
}
|
||||
// The JS SDK eagerly reports itself as "not busy" right after any
|
||||
|
|
|
@ -166,10 +166,11 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
}
|
||||
>();
|
||||
|
||||
let lastTopHeader;
|
||||
let firstBottomHeader;
|
||||
let lastTopHeader: HTMLDivElement | undefined;
|
||||
let firstBottomHeader: HTMLDivElement | undefined;
|
||||
for (const sublist of sublists) {
|
||||
const header = sublist.querySelector<HTMLDivElement>(".mx_RoomSublist_stickable");
|
||||
if (!header) continue; // this should never occur
|
||||
header.style.removeProperty("display"); // always clear display:none first
|
||||
|
||||
// When an element is <=40% off screen, make it take over
|
||||
|
@ -196,7 +197,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
// cause a no-op update, as adding/removing properties that are/aren't there cause
|
||||
// layout updates.
|
||||
for (const header of targetStyles.keys()) {
|
||||
const style = targetStyles.get(header);
|
||||
const style = targetStyles.get(header)!;
|
||||
|
||||
if (style.makeInvisible) {
|
||||
// we will have already removed the 'display: none', so add it back.
|
||||
|
@ -324,7 +325,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
private renderSearchDialExplore(): React.ReactNode {
|
||||
let dialPadButton = null;
|
||||
let dialPadButton: JSX.Element | undefined;
|
||||
|
||||
// If we have dialer support, show a button to bring up the dial pad
|
||||
// to start a new call
|
||||
|
@ -338,7 +339,7 @@ export default class LeftPanel extends React.Component<IProps, IState> {
|
|||
);
|
||||
}
|
||||
|
||||
let rightButton: JSX.Element;
|
||||
let rightButton: JSX.Element | undefined;
|
||||
if (this.state.showBreadcrumbs === BreadcrumbsMode.Labs) {
|
||||
rightButton = <RecentlyViewedButton />;
|
||||
} else if (this.state.activeSpace === MetaSpace.Home && shouldShowComponent(UIComponent.ExploreRooms)) {
|
||||
|
|
|
@ -139,15 +139,15 @@ export default class ViewSource extends React.Component<IProps, IState> {
|
|||
private canSendStateEvent(mxEvent: MatrixEvent): boolean {
|
||||
const cli = MatrixClientPeg.get();
|
||||
const room = cli.getRoom(mxEvent.getRoomId());
|
||||
return room.currentState.mayClientSendStateEvent(mxEvent.getType(), cli);
|
||||
return !!room?.currentState.mayClientSendStateEvent(mxEvent.getType(), cli);
|
||||
}
|
||||
|
||||
public render(): React.ReactNode {
|
||||
const mxEvent = this.props.mxEvent.replacingEvent() || this.props.mxEvent; // show the replacing event, not the original, if it is an edit
|
||||
|
||||
const isEditing = this.state.isEditing;
|
||||
const roomId = mxEvent.getRoomId();
|
||||
const eventId = mxEvent.getId();
|
||||
const roomId = mxEvent.getRoomId()!;
|
||||
const eventId = mxEvent.getId()!;
|
||||
const canEdit = mxEvent.isState() ? this.canSendStateEvent(mxEvent) : canEditContent(this.props.mxEvent);
|
||||
return (
|
||||
<BaseDialog className="mx_ViewSource" onFinished={this.props.onFinished} title={_t("View Source")}>
|
||||
|
|
|
@ -39,6 +39,7 @@ import AuthBody from "../../views/auth/AuthBody";
|
|||
import AuthHeader from "../../views/auth/AuthHeader";
|
||||
import AccessibleButton, { ButtonEvent } from "../../views/elements/AccessibleButton";
|
||||
import { ValidatedServerConfig } from "../../../utils/ValidatedServerConfig";
|
||||
import { filterBoolean } from "../../../utils/arrays";
|
||||
|
||||
// These are used in several places, and come from the js-sdk's autodiscovery
|
||||
// stuff. We define them here so that they'll be picked up by i18n.
|
||||
|
@ -120,15 +121,11 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
|||
|
||||
this.state = {
|
||||
busy: false,
|
||||
busyLoggingIn: null,
|
||||
errorText: null,
|
||||
loginIncorrect: false,
|
||||
canTryLogin: true,
|
||||
|
||||
flows: null,
|
||||
|
||||
username: props.defaultUsername ? props.defaultUsername : "",
|
||||
phoneCountry: null,
|
||||
phoneNumber: "",
|
||||
|
||||
serverIsAlive: true,
|
||||
|
@ -167,7 +164,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
|||
}
|
||||
}
|
||||
|
||||
public isBusy = (): boolean => this.state.busy || this.props.busy;
|
||||
public isBusy = (): boolean => !!this.state.busy || !!this.props.busy;
|
||||
|
||||
public onPasswordLogin: OnPasswordLogin = async (
|
||||
username: string | undefined,
|
||||
|
@ -349,7 +346,7 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
|||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
const ssoKind = ssoFlow.type === "m.login.sso" ? "sso" : "cas";
|
||||
PlatformPeg.get().startSingleSignOn(
|
||||
PlatformPeg.get()?.startSingleSignOn(
|
||||
this.loginLogic.createTemporaryClient(),
|
||||
ssoKind,
|
||||
this.props.fragmentAfterLogin,
|
||||
|
@ -511,13 +508,13 @@ export default class LoginComponent extends React.PureComponent<IProps, IState>
|
|||
return errorText;
|
||||
}
|
||||
|
||||
public renderLoginComponentForFlows(): JSX.Element {
|
||||
public renderLoginComponentForFlows(): ReactNode {
|
||||
if (!this.state.flows) return null;
|
||||
|
||||
// this is the ideal order we want to show the flows in
|
||||
const order = ["m.login.password", "m.login.sso"];
|
||||
|
||||
const flows = order.map((type) => this.state.flows.find((flow) => flow.type === type)).filter(Boolean);
|
||||
const flows = filterBoolean(order.map((type) => this.state.flows.find((flow) => flow.type === type)));
|
||||
return (
|
||||
<React.Fragment>
|
||||
{flows.map((flow) => {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue