Conform more code to strict null checking (#10153)

* Conform more code to strict null checking

* Conform more code to strict null checking

* Iterate

* Iterate
This commit is contained in:
Michael Telatynski 2023-02-15 13:36:22 +00:00 committed by GitHub
parent a4ff959aa1
commit 145a5a8a8d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
89 changed files with 520 additions and 551 deletions

View file

@ -91,7 +91,7 @@ function getLevelOrder(setting: ISetting): SettingLevel[] {
export type CallbackFn = (
settingName: string,
roomId: string,
roomId: string | null,
atLevel: SettingLevel,
newValAtLevel: any,
newVal: any,
@ -133,7 +133,7 @@ export default class SettingsStore {
// when the setting changes. We track which rooms we're monitoring though to ensure we
// don't duplicate updates on the bus.
private static watchers = new Map<string, WatchCallbackFn>();
private static monitors = new Map<string, Map<string, string>>(); // { settingName => { roomId => callbackRef } }
private static monitors = new Map<string, Map<string | null, string>>(); // { settingName => { roomId => callbackRef } }
// Counter used for generation of watcher IDs
private static watcherCount = 1;
@ -205,7 +205,7 @@ export default class SettingsStore {
return;
}
defaultWatchManager.unwatchSetting(SettingsStore.watchers.get(watcherReference));
defaultWatchManager.unwatchSetting(SettingsStore.watchers.get(watcherReference)!);
SettingsStore.watchers.delete(watcherReference);
}
@ -223,7 +223,7 @@ export default class SettingsStore {
if (!this.monitors.has(settingName)) this.monitors.set(settingName, new Map());
const registerWatcher = (): void => {
this.monitors.get(settingName).set(
this.monitors.get(settingName)!.set(
roomId,
SettingsStore.watchSetting(
settingName,
@ -242,7 +242,7 @@ export default class SettingsStore {
);
};
const rooms = Array.from(this.monitors.get(settingName).keys());
const rooms = Array.from(this.monitors.get(settingName)!.keys());
const hasRoom = rooms.find((r) => r === roomId || r === null);
if (!hasRoom) {
registerWatcher();
@ -250,9 +250,9 @@ export default class SettingsStore {
if (roomId === null) {
// Unregister all existing watchers and register the new one
rooms.forEach((roomId) => {
SettingsStore.unwatchSetting(this.monitors.get(settingName).get(roomId));
SettingsStore.unwatchSetting(this.monitors.get(settingName)!.get(roomId));
});
this.monitors.get(settingName).clear();
this.monitors.get(settingName)!.clear();
registerWatcher();
} // else a watcher is already registered for the room, so don't bother registering it again
}
@ -265,7 +265,7 @@ export default class SettingsStore {
* The level to get the display name for; Defaults to 'default'.
* @return {String} The display name for the setting, or null if not found.
*/
public static getDisplayName(settingName: string, atLevel = SettingLevel.DEFAULT): string {
public static getDisplayName(settingName: string, atLevel = SettingLevel.DEFAULT): string | null {
if (!SETTINGS[settingName] || !SETTINGS[settingName].displayName) return null;
let displayName = SETTINGS[settingName].displayName;
@ -296,7 +296,7 @@ export default class SettingsStore {
*/
public static isFeature(settingName: string): boolean {
if (!SETTINGS[settingName]) return false;
return SETTINGS[settingName].isFeature;
return !!SETTINGS[settingName].isFeature;
}
/**
@ -319,7 +319,7 @@ export default class SettingsStore {
}
}
public static getLabGroup(settingName: string): LabGroup {
public static getLabGroup(settingName: string): LabGroup | undefined {
if (SettingsStore.isFeature(settingName)) {
return (<IFeature>SETTINGS[settingName]).labsGroup;
}
@ -333,7 +333,7 @@ export default class SettingsStore {
*/
public static isEnabled(settingName: string): boolean {
if (!SETTINGS[settingName]) return false;
return SETTINGS[settingName].controller ? !SETTINGS[settingName].controller.settingDisabled : true;
return !SETTINGS[settingName].controller?.settingDisabled ?? true;
}
/**
@ -559,7 +559,7 @@ export default class SettingsStore {
throw new Error("Setting '" + settingName + "' does not appear to be a setting.");
}
return level === SettingLevel.DEFAULT || setting.supportedLevels.includes(level);
return level === SettingLevel.DEFAULT || !!setting.supportedLevels?.includes(level);
}
/**
@ -568,7 +568,7 @@ export default class SettingsStore {
* @param {string} settingName The setting name.
* @return {SettingLevel}
*/
public static firstSupportedLevel(settingName: string): SettingLevel {
public static firstSupportedLevel(settingName: string): SettingLevel | null {
// Verify that the setting is actually a setting
const setting = SETTINGS[settingName];
if (!setting) {
@ -723,10 +723,10 @@ export default class SettingsStore {
logger.log(`--- END DEBUG`);
}
private static getHandler(settingName: string, level: SettingLevel): SettingsHandler {
private static getHandler(settingName: string, level: SettingLevel): SettingsHandler | null {
const handlers = SettingsStore.getHandlers(settingName);
if (!handlers[level]) return null;
return handlers[level];
return handlers[level]!;
}
private static getHandlers(settingName: string): HandlerMap {

View file

@ -16,9 +16,9 @@ limitations under the License.
import { SettingLevel } from "./SettingLevel";
export type CallbackFn = (changedInRoomId: string, atLevel: SettingLevel, newValAtLevel: any) => void;
export type CallbackFn = (changedInRoomId: string | null, atLevel: SettingLevel, newValAtLevel: any) => void;
const IRRELEVANT_ROOM: string = null;
const IRRELEVANT_ROOM: string | null = null;
/**
* Generalized management class for dealing with watchers on a per-handler (per-level)
@ -26,13 +26,13 @@ const IRRELEVANT_ROOM: string = null;
* class, which are then proxied outwards to any applicable watchers.
*/
export class WatchManager {
private watchers = new Map<string, Map<string | symbol, CallbackFn[]>>(); // settingName -> roomId -> CallbackFn[]
private watchers = new Map<string, Map<string | null, CallbackFn[]>>(); // settingName -> roomId -> CallbackFn[]
// Proxy for handlers to delegate changes to this manager
public watchSetting(settingName: string, roomId: string | null, cb: CallbackFn): void {
if (!this.watchers.has(settingName)) this.watchers.set(settingName, new Map());
if (!this.watchers.get(settingName).has(roomId)) this.watchers.get(settingName).set(roomId, []);
this.watchers.get(settingName).get(roomId).push(cb);
if (!this.watchers.get(settingName)!.has(roomId)) this.watchers.get(settingName)!.set(roomId, []);
this.watchers.get(settingName)!.get(roomId)!.push(cb);
}
// Proxy for handlers to delegate changes to this manager
@ -59,18 +59,18 @@ export class WatchManager {
if (!this.watchers.has(settingName)) return;
const roomWatchers = this.watchers.get(settingName);
const callbacks = [];
const roomWatchers = this.watchers.get(settingName)!;
const callbacks: CallbackFn[] = [];
if (inRoomId !== null && roomWatchers.has(inRoomId)) {
callbacks.push(...roomWatchers.get(inRoomId));
callbacks.push(...roomWatchers.get(inRoomId)!);
}
if (!inRoomId) {
// Fire updates to all the individual room watchers too, as they probably care about the change higher up.
callbacks.push(...Array.from(roomWatchers.values()).flat(1));
} else if (roomWatchers.has(IRRELEVANT_ROOM)) {
callbacks.push(...roomWatchers.get(IRRELEVANT_ROOM));
callbacks.push(...roomWatchers.get(IRRELEVANT_ROOM)!);
}
for (const callback of callbacks) {

View file

@ -20,6 +20,6 @@ import { SettingLevel } from "../SettingLevel";
export default class ReloadOnChangeController extends SettingController {
public onChange(level: SettingLevel, roomId: string, newValue: any): void {
PlatformPeg.get().reload();
PlatformPeg.get()?.reload();
}
}

View file

@ -53,7 +53,7 @@ export default abstract class SettingController {
* @param {*} newValue The new value for the setting, may be null.
* @return {boolean} Whether the settings change should be accepted.
*/
public async beforeChange(level: SettingLevel, roomId: string, newValue: any): Promise<boolean> {
public async beforeChange(level: SettingLevel, roomId: string | null, newValue: any): Promise<boolean> {
return true;
}
@ -63,7 +63,7 @@ export default abstract class SettingController {
* @param {String} roomId The room ID, may be null.
* @param {*} newValue The new value for the setting, may be null.
*/
public onChange(level: SettingLevel, roomId: string, newValue: any): void {
public onChange(level: SettingLevel, roomId: string | null, newValue: any): void {
// do nothing by default
}

View file

@ -22,7 +22,7 @@ import SettingsHandler from "./SettingsHandler";
*/
export default abstract class AbstractLocalStorageSettingsHandler extends SettingsHandler {
// Shared cache between all subclass instances
private static itemCache = new Map<string, string>();
private static itemCache = new Map<string, string | null>();
private static objectCache = new Map<string, object>();
private static storageListenerBound = false;
@ -51,14 +51,14 @@ export default abstract class AbstractLocalStorageSettingsHandler extends Settin
}
}
protected getItem(key: string): string {
protected getItem(key: string): string | null {
if (!AbstractLocalStorageSettingsHandler.itemCache.has(key)) {
const value = localStorage.getItem(key);
AbstractLocalStorageSettingsHandler.itemCache.set(key, value);
return value;
}
return AbstractLocalStorageSettingsHandler.itemCache.get(key);
return AbstractLocalStorageSettingsHandler.itemCache.get(key)!;
}
protected getBoolean(key: string): boolean | null {
@ -72,7 +72,7 @@ export default abstract class AbstractLocalStorageSettingsHandler extends Settin
protected getObject<T extends object>(key: string): T | null {
if (!AbstractLocalStorageSettingsHandler.objectCache.has(key)) {
try {
const value = JSON.parse(localStorage.getItem(key));
const value = JSON.parse(localStorage.getItem(key)!);
AbstractLocalStorageSettingsHandler.objectCache.set(key, value);
return value;
} catch (err) {

View file

@ -40,7 +40,7 @@ export default class PlatformSettingsHandler extends SettingsHandler {
this.store = {};
// Load setting values as they are async and `getValue` must be synchronous
Object.entries(SETTINGS).forEach(([key, setting]) => {
if (setting.supportedLevels.includes(SettingLevel.PLATFORM) && payload.platform.supportsSetting(key)) {
if (setting.supportedLevels?.includes(SettingLevel.PLATFORM) && payload.platform.supportsSetting(key)) {
payload.platform.getSettingValue(key).then((value: any) => {
this.store[key] = value;
});
@ -50,19 +50,19 @@ export default class PlatformSettingsHandler extends SettingsHandler {
};
public canSetValue(settingName: string, roomId: string): boolean {
return PlatformPeg.get().supportsSetting(settingName);
return PlatformPeg.get()?.supportsSetting(settingName) ?? false;
}
public getValue(settingName: string, roomId: string): any {
return this.store[settingName];
}
public setValue(settingName: string, roomId: string, newValue: any): Promise<void> {
public async setValue(settingName: string, roomId: string, newValue: any): Promise<void> {
this.store[settingName] = newValue; // keep cache up to date for synchronous access
return PlatformPeg.get().setSettingValue(settingName, newValue);
await PlatformPeg.get()?.setSettingValue(settingName, newValue);
}
public isSupported(): boolean {
return PlatformPeg.get().supportsSetting();
return PlatformPeg.get()?.supportsSetting() ?? false;
}
}

View file

@ -44,7 +44,7 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl
}
private onEvent = (event: MatrixEvent, state: RoomState, prevEvent: MatrixEvent): void => {
const roomId = event.getRoomId();
const roomId = event.getRoomId()!;
const room = this.client.getRoom(roomId);
// Note: in tests and during the encryption setup on initial load we might not have
@ -124,7 +124,7 @@ export default class RoomSettingsHandler extends MatrixClientBackedSettingsHandl
let eventType = DEFAULT_SETTINGS_EVENT_TYPE;
if (settingName === "urlPreviewsEnabled") eventType = "org.matrix.room.preview_urls";
return room?.currentState.maySendStateEvent(eventType, this.client.getUserId()) ?? false;
return room?.currentState.maySendStateEvent(eventType, this.client.getUserId()!) ?? false;
}
public isSupported(): boolean {

View file

@ -32,7 +32,7 @@ export default abstract class SettingsHandler {
* @param {String} roomId The room ID to read from, may be null.
* @returns {*} The setting value, or null if not found.
*/
public abstract getValue(settingName: string, roomId: string): any;
public abstract getValue(settingName: string, roomId: string | null): any;
/**
* Sets the value for a particular setting at this level for a particular room.
@ -45,7 +45,7 @@ export default abstract class SettingsHandler {
* @param {*} newValue The new value for the setting, may be null.
* @returns {Promise} Resolves when the setting has been saved.
*/
public abstract setValue(settingName: string, roomId: string, newValue: any): Promise<void>;
public abstract setValue(settingName: string, roomId: string | null, newValue: any): Promise<void>;
/**
* Determines if the current user is able to set the value of the given setting
@ -54,7 +54,7 @@ export default abstract class SettingsHandler {
* @param {String} roomId The room ID to check in, may be null
* @returns {boolean} True if the setting can be set by the user, false otherwise.
*/
public abstract canSetValue(settingName: string, roomId: string): boolean;
public abstract canSetValue(settingName: string, roomId: string | null): boolean;
/**
* Determines if this level is supported on this device.

View file

@ -30,7 +30,7 @@ export class FontWatcher implements IWatcher {
// Externally we tell the user the font is size 15. Internally we use 10.
public static readonly SIZE_DIFF = 5;
private dispatcherRef: string;
private dispatcherRef: string | null;
public constructor() {
this.dispatcherRef = null;
@ -42,6 +42,7 @@ export class FontWatcher implements IWatcher {
}
public stop(): void {
if (!this.dispatcherRef) return;
dis.unregister(this.dispatcherRef);
}
@ -77,7 +78,7 @@ export class FontWatcher implements IWatcher {
if (fontSize !== size) {
SettingsStore.setValue("baseFontSize", null, SettingLevel.DEVICE, fontSize);
}
document.querySelector<HTMLElement>(":root").style.fontSize = toPx(fontSize);
document.querySelector<HTMLElement>(":root")!.style.fontSize = toPx(fontSize);
};
private setSystemFont = ({

View file

@ -26,9 +26,9 @@ import { ActionPayload } from "../../dispatcher/payloads";
import { SettingLevel } from "../SettingLevel";
export default class ThemeWatcher {
private themeWatchRef: string;
private systemThemeWatchRef: string;
private dispatcherRef: string;
private themeWatchRef: string | null;
private systemThemeWatchRef: string | null;
private dispatcherRef: string | null;
private preferDark: MediaQueryList;
private preferLight: MediaQueryList;
@ -67,9 +67,9 @@ export default class ThemeWatcher {
this.preferLight.removeEventListener("change", this.onChange);
this.preferHighContrast.removeEventListener("change", this.onChange);
}
SettingsStore.unwatchSetting(this.systemThemeWatchRef);
SettingsStore.unwatchSetting(this.themeWatchRef);
dis.unregister(this.dispatcherRef);
if (this.systemThemeWatchRef) SettingsStore.unwatchSetting(this.systemThemeWatchRef);
if (this.themeWatchRef) SettingsStore.unwatchSetting(this.themeWatchRef);
if (this.dispatcherRef) dis.unregister(this.dispatcherRef);
}
private onChange = (): void => {