Skip to content

Commit da7aa40

Browse files
authored
Conform more of the code base to strict null checking (matrix-org#10147)
* Conform more of the code base to strict null checking * More strict fixes * More strict work * Fix missing optional type * Iterate
1 parent fa036a5 commit da7aa40

File tree

380 files changed

+682
-694
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

380 files changed

+682
-694
lines changed

src/AsyncWrapper.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export default class AsyncWrapper extends React.Component<IProps, IState> {
7474
this.props.onFinished(false);
7575
};
7676

77-
public render(): JSX.Element {
77+
public render(): React.ReactNode {
7878
if (this.state.component) {
7979
const Component = this.state.component;
8080
return <Component {...this.props} />;

src/Avatar.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ export function getInitialLetter(name: string): string | undefined {
138138
}
139139

140140
export function avatarUrlForRoom(
141-
room: Room,
141+
room: Room | null,
142142
width: number,
143143
height: number,
144144
resizeMethod?: ResizeMethod,

src/HtmlUtils.tsx

+14-16
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ const transformTags: IExtendedSanitizeOptions["transformTags"] = {
204204
attribs.style += "height: 100%;";
205205
}
206206

207-
attribs.src = mediaFromMxc(src).getThumbnailOfSourceHttp(width, height);
207+
attribs.src = mediaFromMxc(src).getThumbnailOfSourceHttp(width, height)!;
208208
return { tagName, attribs };
209209
},
210210
"code": function (tagName: string, attribs: sanitizeHtml.Attributes) {
@@ -352,7 +352,7 @@ const topicSanitizeHtmlParams: IExtendedSanitizeOptions = {
352352
};
353353

354354
abstract class BaseHighlighter<T extends React.ReactNode> {
355-
public constructor(public highlightClass: string, public highlightLink: string) {}
355+
public constructor(public highlightClass: string, public highlightLink?: string) {}
356356

357357
/**
358358
* apply the highlights to a section of text
@@ -504,7 +504,7 @@ function formatEmojis(message: string, isHtmlMessage: boolean): (JSX.Element | s
504504
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnString): string;
505505
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOptsReturnNode): ReactNode;
506506
export function bodyToHtml(content: IContent, highlights: Optional<string[]>, opts: IOpts = {}): ReactNode | string {
507-
const isFormattedBody = content.format === "org.matrix.custom.html" && !!content.formatted_body;
507+
const isFormattedBody = content.format === "org.matrix.custom.html" && typeof content.formatted_body === "string";
508508
let bodyHasEmoji = false;
509509
let isHtmlMessage = false;
510510

@@ -514,7 +514,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
514514
}
515515

516516
let strippedBody: string;
517-
let safeBody: string; // safe, sanitised HTML, preferred over `strippedBody` which is fully plaintext
517+
let safeBody: string | undefined; // safe, sanitised HTML, preferred over `strippedBody` which is fully plaintext
518518

519519
try {
520520
// sanitizeHtml can hang if an unclosed HTML tag is thrown at it
@@ -529,7 +529,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
529529

530530
if (opts.stripReplyFallback && formattedBody) formattedBody = stripHTMLReply(formattedBody);
531531
strippedBody = opts.stripReplyFallback ? stripPlainReply(plainBody) : plainBody;
532-
bodyHasEmoji = mightContainEmoji(isFormattedBody ? formattedBody : plainBody);
532+
bodyHasEmoji = mightContainEmoji(isFormattedBody ? formattedBody! : plainBody);
533533

534534
const highlighter = safeHighlights?.length
535535
? new HtmlHighlighter("mx_EventTile_searchHighlight", opts.highlightLink)
@@ -543,11 +543,11 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
543543
// by an attempt to search for 'foobar'. Then again, the search query probably wouldn't work either
544544
// XXX: hacky bodge to temporarily apply a textFilter to the sanitizeParams structure.
545545
sanitizeParams.textFilter = function (safeText) {
546-
return highlighter.applyHighlights(safeText, safeHighlights).join("");
546+
return highlighter.applyHighlights(safeText, safeHighlights!).join("");
547547
};
548548
}
549549

550-
safeBody = sanitizeHtml(formattedBody, sanitizeParams);
550+
safeBody = sanitizeHtml(formattedBody!, sanitizeParams);
551551
const phtml = cheerio.load(safeBody, {
552552
// @ts-ignore: The `_useHtmlParser2` internal option is the
553553
// simplest way to both parse and render using `htmlparser2`.
@@ -574,7 +574,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
574574
safeBody = formatEmojis(safeBody, true).join("");
575575
}
576576
} else if (highlighter) {
577-
safeBody = highlighter.applyHighlights(plainBody, safeHighlights).join("");
577+
safeBody = highlighter.applyHighlights(plainBody, safeHighlights!).join("");
578578
}
579579
} finally {
580580
delete sanitizeParams.textFilter;
@@ -597,9 +597,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
597597

598598
const match = BIGEMOJI_REGEX.exec(contentBodyTrimmed);
599599
emojiBody =
600-
match &&
601-
match[0] &&
602-
match[0].length === contentBodyTrimmed.length &&
600+
match?.[0]?.length === contentBodyTrimmed.length &&
603601
// Prevent user pills expanding for users with only emoji in
604602
// their username. Permalinks (links in pills) can be any URL
605603
// now, so we just check for an HTTP-looking thing.
@@ -614,7 +612,7 @@ export function bodyToHtml(content: IContent, highlights: Optional<string[]>, op
614612
"markdown-body": isHtmlMessage && !emojiBody,
615613
});
616614

617-
let emojiBodyElements: JSX.Element[];
615+
let emojiBodyElements: JSX.Element[] | undefined;
618616
if (!safeBody && bodyHasEmoji) {
619617
emojiBodyElements = formatEmojis(strippedBody, false) as JSX.Element[];
620618
}
@@ -649,18 +647,18 @@ export function topicToHtml(
649647
allowExtendedHtml = false,
650648
): ReactNode {
651649
if (!SettingsStore.getValue("feature_html_topic")) {
652-
htmlTopic = null;
650+
htmlTopic = undefined;
653651
}
654652

655653
let isFormattedTopic = !!htmlTopic;
656654
let topicHasEmoji = false;
657655
let safeTopic = "";
658656

659657
try {
660-
topicHasEmoji = mightContainEmoji(isFormattedTopic ? htmlTopic : topic);
658+
topicHasEmoji = mightContainEmoji(isFormattedTopic ? htmlTopic! : topic);
661659

662660
if (isFormattedTopic) {
663-
safeTopic = sanitizeHtml(htmlTopic, allowExtendedHtml ? sanitizeHtmlParams : topicSanitizeHtmlParams);
661+
safeTopic = sanitizeHtml(htmlTopic!, allowExtendedHtml ? sanitizeHtmlParams : topicSanitizeHtmlParams);
664662
if (topicHasEmoji) {
665663
safeTopic = formatEmojis(safeTopic, true).join("");
666664
}
@@ -669,7 +667,7 @@ export function topicToHtml(
669667
isFormattedTopic = false; // Fall back to plain-text topic
670668
}
671669

672-
let emojiBodyElements: ReturnType<typeof formatEmojis>;
670+
let emojiBodyElements: ReturnType<typeof formatEmojis> | undefined;
673671
if (!isFormattedTopic && topicHasEmoji) {
674672
emojiBodyElements = formatEmojis(topic, false);
675673
}

src/Markdown.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export default class Markdown {
139139
*/
140140
private repairLinks(parsed: commonmark.Node): commonmark.Node {
141141
const walker = parsed.walker();
142-
let event: commonmark.NodeWalkingStep = null;
142+
let event: commonmark.NodeWalkingStep | null = null;
143143
let text = "";
144144
let isInPara = false;
145145
let previousNode: commonmark.Node | null = null;
@@ -287,7 +287,7 @@ export default class Markdown {
287287
// However, if it's a blockquote, adds a p tag anyway
288288
// in order to avoid deviation to commonmark and unexpected
289289
// results when parsing the formatted HTML.
290-
if (node.parent.type === "block_quote" || isMultiLine(node)) {
290+
if (node.parent?.type === "block_quote" || isMultiLine(node)) {
291291
realParagraph.call(this, node, entering);
292292
}
293293
};

src/NodeAnimator.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export default class NodeAnimator extends React.Component<IProps> {
120120
this.nodes[k] = node;
121121
}
122122

123-
public render(): JSX.Element {
123+
public render(): React.ReactNode {
124124
return <>{Object.values(this.children)}</>;
125125
}
126126
}

src/PosthogTrackers.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export class PosthogScreenTracker extends PureComponent<{ screenName: ScreenName
120120
PosthogTrackers.instance.clearOverride(this.props.screenName);
121121
}
122122

123-
public render(): JSX.Element {
123+
public render(): React.ReactNode {
124124
return null; // no need to render anything, we just need to hook into the React lifecycle
125125
}
126126
}

src/Presence.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ enum State {
3333
}
3434

3535
class Presence {
36-
private unavailableTimer: Timer = null;
37-
private dispatcherRef: string = null;
38-
private state: State = null;
36+
private unavailableTimer: Timer | null = null;
37+
private dispatcherRef: string | null = null;
38+
private state: State | null = null;
3939

4040
/**
4141
* Start listening the user activity to evaluate his presence state.
@@ -73,14 +73,14 @@ class Presence {
7373
* Get the current presence state.
7474
* @returns {string} the presence state (see PRESENCE enum)
7575
*/
76-
public getState(): State {
76+
public getState(): State | null {
7777
return this.state;
7878
}
7979

8080
private onAction = (payload: ActionPayload): void => {
8181
if (payload.action === "user_activity") {
8282
this.setState(State.Online);
83-
this.unavailableTimer.restart();
83+
this.unavailableTimer?.restart();
8484
}
8585
};
8686

src/Resend.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export default class Resend {
4646
}
4747

4848
public static resend(event: MatrixEvent): Promise<void> {
49-
const room = MatrixClientPeg.get().getRoom(event.getRoomId());
49+
const room = MatrixClientPeg.get().getRoom(event.getRoomId())!;
5050
return MatrixClientPeg.get()
5151
.resendEvent(event, room)
5252
.then(

src/RoomAliasCache.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,6 @@ export function storeRoomAliasInCache(alias: string, id: string): void {
3030
aliasToIDMap.set(alias, id);
3131
}
3232

33-
export function getCachedRoomIDForAlias(alias: string): string {
33+
export function getCachedRoomIDForAlias(alias: string): string | undefined {
3434
return aliasToIDMap.get(alias);
3535
}

src/RoomInvite.tsx

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ export function inviteUsersToRoom(
112112
): Promise<void> {
113113
return inviteMultipleToRoom(roomId, userIds, sendSharedHistoryKeys, progressCallback)
114114
.then((result) => {
115-
const room = MatrixClientPeg.get().getRoom(roomId);
115+
const room = MatrixClientPeg.get().getRoom(roomId)!;
116116
showAnyInviteErrors(result.states, room, result.inviter);
117117
})
118118
.catch((err) => {
@@ -175,14 +175,14 @@ export function showAnyInviteErrors(
175175
<BaseAvatar
176176
url={avatarUrl ? mediaFromMxc(avatarUrl).getSquareThumbnailHttp(24) : null}
177177
name={name}
178-
idName={user.userId}
178+
idName={user?.userId}
179179
width={36}
180180
height={36}
181181
/>
182182
</div>
183183
<div className="mx_InviteDialog_tile_nameStack">
184184
<span className="mx_InviteDialog_tile_nameStack_name">{name}</span>
185-
<span className="mx_InviteDialog_tile_nameStack_userId">{user.userId}</span>
185+
<span className="mx_InviteDialog_tile_nameStack_userId">{user?.userId}</span>
186186
</div>
187187
<div className="mx_InviteDialog_tile--inviterError_errorText">
188188
{inviter.getErrorText(addr)}

src/RoomNotifs.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export function getRoomNotifsState(client: MatrixClient, roomId: string): RoomNo
4646
}
4747

4848
// for everything else, look at the room rule.
49-
let roomRule = null;
49+
let roomRule: IPushRule | undefined;
5050
try {
5151
roomRule = client.getRoomPushRule("global", roomId);
5252
} catch (err) {
@@ -106,7 +106,7 @@ export function getUnreadNotificationCount(room: Room, type: NotificationCountTy
106106

107107
function setRoomNotifsStateMuted(roomId: string): Promise<any> {
108108
const cli = MatrixClientPeg.get();
109-
const promises = [];
109+
const promises: Promise<unknown>[] = [];
110110

111111
// delete the room rule
112112
const roomRule = cli.getRoomPushRule("global", roomId);
@@ -137,7 +137,7 @@ function setRoomNotifsStateMuted(roomId: string): Promise<any> {
137137

138138
function setRoomNotifsStateUnmuted(roomId: string, newState: RoomNotifState): Promise<any> {
139139
const cli = MatrixClientPeg.get();
140-
const promises = [];
140+
const promises: Promise<unknown>[] = [];
141141

142142
const overrideMuteRule = findOverrideMuteRule(roomId);
143143
if (overrideMuteRule) {

src/Rooms.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,13 @@ import AliasCustomisations from "./customisations/Alias";
2929
* @param {Object} room The room object
3030
* @returns {string} A display alias for the given room
3131
*/
32-
export function getDisplayAliasForRoom(room: Room): string | undefined {
32+
export function getDisplayAliasForRoom(room: Room): string | null {
3333
return getDisplayAliasForAliasSet(room.getCanonicalAlias(), room.getAltAliases());
3434
}
3535

3636
// The various display alias getters should all feed through this one path so
3737
// there's a single place to change the logic.
38-
export function getDisplayAliasForAliasSet(canonicalAlias: string, altAliases: string[]): string {
38+
export function getDisplayAliasForAliasSet(canonicalAlias: string | null, altAliases: string[]): string | null {
3939
if (AliasCustomisations.getDisplayAliasForAliasSet) {
4040
return AliasCustomisations.getDisplayAliasForAliasSet(canonicalAlias, altAliases);
4141
}
@@ -45,7 +45,7 @@ export function getDisplayAliasForAliasSet(canonicalAlias: string, altAliases: s
4545
export function guessAndSetDMRoom(room: Room, isDirect: boolean): Promise<void> {
4646
let newTarget;
4747
if (isDirect) {
48-
const guessedUserId = guessDMRoomTargetId(room, MatrixClientPeg.get().getUserId());
48+
const guessedUserId = guessDMRoomTargetId(room, MatrixClientPeg.get().getUserId()!);
4949
newTarget = guessedUserId;
5050
} else {
5151
newTarget = null;
@@ -118,7 +118,7 @@ function guessDMRoomTargetId(room: Room, myUserId: string): string {
118118

119119
if (oldestTs === undefined || (user.events.member && user.events.member.getTs() < oldestTs)) {
120120
oldestUser = user;
121-
oldestTs = user.events.member.getTs();
121+
oldestTs = user.events.member?.getTs();
122122
}
123123
}
124124
if (oldestUser) return oldestUser.userId;
@@ -129,7 +129,7 @@ function guessDMRoomTargetId(room: Room, myUserId: string): string {
129129

130130
if (oldestTs === undefined || (user.events.member && user.events.member.getTs() < oldestTs)) {
131131
oldestUser = user;
132-
oldestTs = user.events.member.getTs();
132+
oldestTs = user.events.member?.getTs();
133133
}
134134
}
135135

src/VoipUserMapper.ts

+6-6
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ export default class VoipUserMapper {
7272
* Gets the ID of the virtual room for a room, or null if the room has no
7373
* virtual room
7474
*/
75-
public async getVirtualRoomForRoom(roomId: string): Promise<Room | null> {
75+
public async getVirtualRoomForRoom(roomId: string): Promise<Room | undefined> {
7676
const virtualUser = await this.getVirtualUserForRoom(roomId);
77-
if (!virtualUser) return null;
77+
if (!virtualUser) return undefined;
7878

7979
return findDMForUser(MatrixClientPeg.get(), virtualUser);
8080
}
@@ -145,11 +145,11 @@ export default class VoipUserMapper {
145145
// (possibly we should only join if we've also joined the native room, then we'd also have
146146
// to make sure we joined virtual rooms on joining a native one)
147147
MatrixClientPeg.get().joinRoom(invitedRoom.roomId);
148-
}
149148

150-
// also put this room in the virtual room ID cache so isVirtualRoom return the right answer
151-
// in however long it takes for the echo of setAccountData to come down the sync
152-
this.virtualToNativeRoomIdCache.set(invitedRoom.roomId, nativeRoom.roomId);
149+
// also put this room in the virtual room ID cache so isVirtualRoom return the right answer
150+
// in however long it takes for the echo of setAccountData to come down the sync
151+
this.virtualToNativeRoomIdCache.set(invitedRoom.roomId, nativeRoom.roomId);
152+
}
153153
}
154154
}
155155
}

src/async-components/views/dialogs/eventindex/ManageEventIndexDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
143143
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
144144
};
145145

146-
public render(): JSX.Element {
146+
public render(): React.ReactNode {
147147
const brand = SdkConfig.get().brand;
148148

149149
let crawlerState;

src/async-components/views/dialogs/security/CreateKeyBackupDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -459,7 +459,7 @@ export default class CreateKeyBackupDialog extends React.PureComponent<IProps, I
459459
}
460460
}
461461

462-
public render(): JSX.Element {
462+
public render(): React.ReactNode {
463463
let content;
464464
if (this.state.error) {
465465
content = (

src/async-components/views/dialogs/security/CreateSecretStorageDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -842,7 +842,7 @@ export default class CreateSecretStorageDialog extends React.PureComponent<IProp
842842
}
843843
}
844844

845-
public render(): JSX.Element {
845+
public render(): React.ReactNode {
846846
let content;
847847
if (this.state.error) {
848848
content = (

src/async-components/views/dialogs/security/ExportE2eKeysDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export default class ExportE2eKeysDialog extends React.Component<IProps, IState>
127127
} as Pick<IState, AnyPassphrase>);
128128
};
129129

130-
public render(): JSX.Element {
130+
public render(): React.ReactNode {
131131
const disableForm = this.state.phase === Phase.Exporting;
132132

133133
return (

src/async-components/views/dialogs/security/ImportE2eKeysDialog.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ export default class ImportE2eKeysDialog extends React.Component<IProps, IState>
127127
return false;
128128
};
129129

130-
public render(): JSX.Element {
130+
public render(): React.ReactNode {
131131
const disableForm = this.state.phase !== Phase.Edit;
132132

133133
return (

0 commit comments

Comments
 (0)