Reputation: 1197
So i have this constants class
which defines the names of the variables that i save to the localStorage
/ chrome.storage
and what their default value is if the items doesn't exist in the storage.
SettingsConstants.ts
export class SettingsConstants {
public static SETTINGS_ALLOWED: string = "settingsAllowed";
public static QUIT_ALLOWED: string = "quitAllowed";
public static DEFAULTS: any = () => {
const defaults = {};
defaults[SettingsConstant.SETTINGS_ALLOWED] = true;
defaults[SettingsConstant.QUIT_ALLOWED] = true;
return defaults;
};
public static STORAGE_STRINGS: string[] = [
SettingsConstant.SETTINGS_ALLOWED,
SettingsConstant.QUIT_ALLOWED
]
}
Then i have SettingsService
which uses these constants in the getItemsFromStorage()
method. Basically what it does is that it loops through the strings defined in SettingsConstants
and sets it own properties
equal to the value
it got from the storage
, otherwise set the default value
.
SettingsService.ts
export class SettingsService implements ISettingsService {
private settingsAllowed: boolean = undefined;
private quitAllowed: boolean = undefined;
constructor(logger: Logger) {
this.logger = logger;
this.getItemsFromStorage();
}
private getItemsFromStorage(): void {
const storageStrings: string[] = SettingsConstant.STORAGE_STRINGS;
for (let i = 0; i < storageStrings.length; i++) {
const currentString = storageStrings[i];
if (!this.hasOwnProperty(currentString)) {
throw "The property is not defined, " +
"check if it matches the STORAGE_STRING in SettingsConstants";
}
const currentItem = this.getItem(currentString);
this[currentString] = currentItem === undefined
? SettingsConstant.DEFAULTS()[currentString]
: currentItem;
this.logger.log(currentString, "=", this[currentString]);
}
}
private getItem(item: any): any {
const localItem: string = localStorage.getItem(item);
if (localItem === undefined || localItem === null || localItem === 'undefined') {
return undefined;
} else {
return JSON.parse(localItem);
}
}
}
The code works, but it isn't statically checked, which is what i desire. The current way to check if SettingsService
has a property
is to set the property
to undefined
then use
if (!this.hasOwnProperty(currentString)) {
throw "The property is not defined, " +
"check if it matches the STORAGE_STRING in SettingsConstants";
}
To check if the variable exists in the class
, if it doesn't then it must mean that we might have misspelled it, or forgotten to add it.
I could solve this problem by adding them to the ISettingsService
interface
, that would however mean that the property
would become public
which is not the intention
My desired solution
I would like to define a type where i could define the names of the variables that were allowed to be used. Similar to this
export declare namespace SettingsTypes{
type SettingsType = "settingsAllowed" | "quitAllowed";
}
Then in SettingsService
i could write the following
private settingsAllowed: SettingsTypes.SettingType: boolean;
So its like settingsAllowed
name has to be of type SettingsTypes.SettingType
and its return type would be boolean
However this does not seem to make much sense, and it seems like there is no way to do this properly, so i was wondering if any of you bright heads might have a great solution for this problem.
Upvotes: 0
Views: 69
Reputation: 3243
It’s an interesting question. I went to read some documentation. Have a look at the section of the type guards in particular. Perhaps you can do something similar where you do a type guard for boolean?
function isSetting(setting: any): setting is Settings {
return typeof setting === SettingsTypes.SettingType;
}
Something similar to this. It’s just a possible idea
Upvotes: 1