Skip to content

Commit 5ff3025

Browse files
t3chguyHalf-Shot
andauthored
Harden settings types (#33311)
* Harden settings types * Fix types * Update apps/web/src/emojipicker/recent.ts Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com> * Fix suggestion --------- Co-authored-by: Will Hunt <2072976+Half-Shot@users.noreply.github.com>
1 parent 4bee845 commit 5ff3025

26 files changed

Lines changed: 104 additions & 97 deletions

File tree

apps/web/src/@types/media_preview.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,9 @@ export interface MediaPreviewConfig extends Record<string, unknown> {
2525
/**
2626
* Media preview setting for thumbnails of media in rooms.
2727
*/
28-
media_previews: MediaPreviewValue;
28+
media_previews?: MediaPreviewValue;
2929
/**
3030
* Media preview settings for avatars of rooms we have been invited to.
3131
*/
32-
invite_avatars: MediaPreviewValue.On | MediaPreviewValue.Off;
32+
invite_avatars?: MediaPreviewValue.On | MediaPreviewValue.Off;
3333
}

apps/web/src/LegacyCallHandler.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -725,7 +725,7 @@ export default class LegacyCallHandler extends TypedEventEmitter<LegacyCallHandl
725725
);
726726

727727
finished.then(([allow]) => {
728-
SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow);
728+
SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow ?? null);
729729
});
730730
}
731731

apps/web/src/Notifier.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,16 @@ interface EmittedEvents {
142142
[NotifierEvent.NotificationHiddenChange]: (hidden: boolean) => void;
143143
}
144144

145+
/**
146+
* Type representing a notification sound setting
147+
*/
148+
export type NotificationSound = {
149+
url: string;
150+
name?: string;
151+
type?: string;
152+
size?: number;
153+
};
154+
145155
class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents> {
146156
private notifsByRoom: Record<string, Notification[]> = {};
147157

@@ -223,12 +233,7 @@ class NotifierClass extends TypedEventEmitter<keyof EmittedEvents, EmittedEvents
223233
}
224234
}
225235

226-
public getSoundForRoom(roomId: string): {
227-
url: string;
228-
name: string;
229-
type: string;
230-
size: number;
231-
} | null {
236+
public getSoundForRoom(roomId: string): NotificationSound | null {
232237
// We do no caching here because the SDK caches setting
233238
// and the browser will cache the sound.
234239
const content = SettingsStore.getValue("notificationSound", roomId);

apps/web/src/PosthogAnalytics.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import SettingsStore from "./settings/SettingsStore";
1919
import { type ScreenName } from "./PosthogTrackers";
2020
import { type ActionPayload } from "./dispatcher/payloads";
2121
import { Action } from "./dispatcher/actions";
22-
import { type SettingUpdatedPayload } from "./dispatcher/payloads/SettingUpdatedPayload";
22+
import { isSettingUpdatedPayload, type SettingUpdatedPayload } from "./dispatcher/payloads/SettingUpdatedPayload";
2323
import dis from "./dispatcher/dispatcher";
2424
import { Layout } from "./settings/enums/Layout";
2525

@@ -199,8 +199,8 @@ export class PosthogAnalytics {
199199
const settingsPayload = payload as SettingUpdatedPayload;
200200
if (["layout", "useCompactLayout"].includes(settingsPayload.settingName)) {
201201
this.onLayoutUpdated();
202-
} else if (settingsPayload.settingName === "urlPreviewsEnabled" && !settingsPayload.roomId) {
203-
this.onUrlPreviewSettingUpdated(settingsPayload.newValue as boolean);
202+
} else if (isSettingUpdatedPayload(settingsPayload, "urlPreviewsEnabled") && !settingsPayload.roomId) {
203+
this.onUrlPreviewSettingUpdated(settingsPayload.newValue);
204204
}
205205
};
206206

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ export default class ManageEventIndexDialog extends React.Component<IProps, ISta
122122

123123
private onCrawlerSleepTimeChange = (e: ChangeEvent<HTMLInputElement>): void => {
124124
this.setState({ crawlerSleepTime: parseInt(e.target.value, 10) });
125-
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.value);
125+
SettingsStore.setValue("crawlerSleepTime", null, SettingLevel.DEVICE, e.target.valueAsNumber);
126126
};
127127

128128
public render(): React.ReactNode {

apps/web/src/components/structures/MatrixChat.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,11 +1794,11 @@ export default class MatrixChat extends React.PureComponent<IProps, IState> {
17941794
SettingsStore.watchSetting(
17951795
"blacklistUnverifiedDevices",
17961796
null,
1797-
(_settingName, _roomId, atLevel, blacklistEnabled: boolean) => {
1797+
(_settingName, _roomId, atLevel, blacklistEnabled) => {
17981798
if (atLevel != SettingLevel.DEVICE) {
17991799
return;
18001800
}
1801-
crypto.globalBlacklistUnverifiedDevices = blacklistEnabled;
1801+
crypto.globalBlacklistUnverifiedDevices = !!blacklistEnabled;
18021802
},
18031803
);
18041804
}

apps/web/src/components/views/settings/LayoutSwitcher.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ function LayoutSelector(): JSX.Element {
3838
<Root
3939
className="mx_LayoutSwitcher_LayoutSelector"
4040
onChange={async (evt) => {
41-
// We don't have any file in the form, we can cast it as string safely
42-
const newLayout = new FormData(evt.currentTarget).get("layout") as string | null;
41+
// We don't have any file in the form, we can cast it as Layout safely
42+
const newLayout = new FormData(evt.currentTarget).get("layout") as Layout;
4343
await SettingsStore.setValue("layout", null, SettingLevel.DEVICE, newLayout);
4444
}}
4545
>

apps/web/src/components/views/settings/tabs/user/PreferencesUserSettingsTab.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -211,17 +211,17 @@ export default class PreferencesUserSettingsTab extends React.Component<IProps,
211211

212212
private onAutocompleteDelayChange = (e: React.ChangeEvent<HTMLInputElement>): void => {
213213
this.setState({ autocompleteDelay: e.target.value });
214-
SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.value);
214+
SettingsStore.setValue("autocompleteDelay", null, SettingLevel.DEVICE, e.target.valueAsNumber);
215215
};
216216

217217
private onReadMarkerInViewThresholdMs = (e: React.ChangeEvent<HTMLInputElement>): void => {
218218
this.setState({ readMarkerInViewThresholdMs: e.target.value });
219-
SettingsStore.setValue("readMarkerInViewThresholdMs", null, SettingLevel.DEVICE, e.target.value);
219+
SettingsStore.setValue("readMarkerInViewThresholdMs", null, SettingLevel.DEVICE, e.target.valueAsNumber);
220220
};
221221

222222
private onReadMarkerOutOfViewThresholdMs = (e: React.ChangeEvent<HTMLInputElement>): void => {
223223
this.setState({ readMarkerOutOfViewThresholdMs: e.target.value });
224-
SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.value);
224+
SettingsStore.setValue("readMarkerOutOfViewThresholdMs", null, SettingLevel.DEVICE, e.target.valueAsNumber);
225225
};
226226

227227
private renderGroup(settingIds: BooleanSettingKey[], level = SettingLevel.ACCOUNT): JSX.Element {

apps/web/src/device-listener/DeviceListener.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ export class DeviceListener {
340340
});
341341
}
342342

343-
private onRecordClientInformationSettingChange: CallbackFn = (
343+
private onRecordClientInformationSettingChange: CallbackFn<"deviceClientInformationOptIn"> = (
344344
_originalSettingName,
345345
_roomId,
346346
_level,

apps/web/src/dispatcher/payloads/SettingUpdatedPayload.ts

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,26 @@ Please see LICENSE files in the repository root for full details.
99
import { type ActionPayload } from "../payloads";
1010
import { type Action } from "../actions";
1111
import { type SettingLevel } from "../../settings/SettingLevel";
12-
import { type SettingValueType } from "../../settings/Settings";
12+
import { type SettingKey, type Settings } from "../../settings/Settings";
1313

14-
export interface SettingUpdatedPayload extends ActionPayload {
14+
export interface SettingUpdatedPayload<S extends SettingKey = SettingKey> extends ActionPayload {
1515
action: Action.SettingUpdated;
1616

17-
settingName: string;
17+
settingName: S;
1818
roomId: string | null;
1919
level: SettingLevel;
20-
newValueAtLevel: SettingLevel;
21-
newValue: SettingValueType;
20+
newValueAtLevel: Settings[S]["default"];
21+
newValue: Settings[S]["default"];
22+
}
23+
24+
/**
25+
* Type guard to check if a payload is a SettingUpdatedPayload for a specific setting.
26+
* @param payload the payload to assert
27+
* @param settingName the setting name to check for
28+
*/
29+
export function isSettingUpdatedPayload<S extends SettingKey>(
30+
payload: SettingUpdatedPayload<any>,
31+
settingName: S,
32+
): payload is SettingUpdatedPayload<S> {
33+
return payload.settingName === settingName;
2234
}

0 commit comments

Comments
 (0)