Strongly type useSettings (supersedes #559)

This commit is contained in:
Vendicated 2023-03-04 18:40:37 +01:00
parent 92372bde1d
commit cab72e1be6
No known key found for this signature in database
GPG key ID: A1DC0CFB5615D905
2 changed files with 16 additions and 4 deletions

View file

@ -167,11 +167,11 @@ export const Settings = makeProxy(settings);
* @returns Settings * @returns Settings
*/ */
// TODO: Representing paths as essentially "string[].join('.')" wont allow dots in paths, change to "paths?: string[][]" later // TODO: Representing paths as essentially "string[].join('.')" wont allow dots in paths, change to "paths?: string[][]" later
export function useSettings(paths?: string[]) { export function useSettings(paths?: UseSettings<Settings>[]) {
const [, forceUpdate] = React.useReducer(() => ({}), {}); const [, forceUpdate] = React.useReducer(() => ({}), {});
const onUpdate: SubscriptionCallback = paths const onUpdate: SubscriptionCallback = paths
? (value, path) => paths.includes(path) && forceUpdate() ? (value, path) => paths.includes(path as UseSettings<Settings>) && forceUpdate()
: forceUpdate; : forceUpdate;
React.useEffect(() => { React.useEffect(() => {
@ -229,7 +229,7 @@ export function definePluginSettings<D extends SettingsDefinition, C extends Set
return Settings.plugins[definedSettings.pluginName] as any; return Settings.plugins[definedSettings.pluginName] as any;
}, },
use: settings => useSettings( use: settings => useSettings(
settings?.map(name => `plugins.${definedSettings.pluginName}.${name}`) settings?.map(name => `plugins.${definedSettings.pluginName}.${name}`) as UseSettings<Settings>[]
).plugins[definedSettings.pluginName] as any, ).plugins[definedSettings.pluginName] as any,
def, def,
checks: checks ?? {}, checks: checks ?? {},
@ -237,3 +237,15 @@ export function definePluginSettings<D extends SettingsDefinition, C extends Set
}; };
return definedSettings; return definedSettings;
} }
type UseSettings<T extends object> = ResolveUseSettings<T>[keyof T];
type ResolveUseSettings<T extends object> = {
[Key in keyof T]:
Key extends string
? T[Key] extends Record<string, unknown>
// @ts-ignore "Type instantiation is excessively deep and possibly infinite"
? UseSettings<T[Key]> extends string ? `${Key}.${UseSettings<T[Key]>}` : never
: Key
: never;
};

View file

@ -93,7 +93,7 @@ interface PluginCardProps extends React.HTMLProps<HTMLDivElement> {
} }
function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) { function PluginCard({ plugin, disabled, onRestartNeeded, onMouseEnter, onMouseLeave, isNew }: PluginCardProps) {
const settings = useSettings([`plugins.${plugin.name}`]).plugins[plugin.name]; const settings = useSettings([`plugins.${plugin.name}.enabled`]).plugins[plugin.name];
const isEnabled = () => settings.enabled ?? false; const isEnabled = () => settings.enabled ?? false;