I've made an API call that returns a string, for example "clear". I've made an enum SkyGradients to match this string:
export enum SkyGradients {
Overcast = "linear-gradient(135deg, #808080, #404040)",
Clear = "linear-gradient(135deg, #C0C0C0, #808080)",
}
as well as SkyColors:
export enum SkyColors {
Overcast = "rgb(128, 128, 128)",
Clear = "rgb(192, 192, 192)",
}
Now what I want to do is get the corresponding color and gradient using the string: "Clear"
I've tried this:
export function getGradients(text: string): string | undefined {
for (const gradient in Gradients) {
if (Gradients[gradient] === text) {
return gradient;
}
}
}
But I'm getting this error:
'Gradients' only refers to a type, but is being used a value here.
as well as:
Element implicitly has an 'any' type because of type 'string' can't be used to index type 'typeof Gradients'. No index signature with a parameter of type 'string' was found on type 'typeof Gradients'
I understand the errors but unsure how to fix
Unless there's some reason you really want an enum pattern, seems like a better solution would be
export type SkyFills = {
Overcast: string,
Clear: string,
[key: string]: string | undefined // This lets you index with any string
}
export const skyGradients: SkyFills = {
Overcast: "linear-gradient(135deg, #808080, #404040)",
Clear: "linear-gradient(135deg, #C0C0C0, #808080)",
};
export const skyColors: SkyFills = {
Overcast: "rgb(128, 128, 128)",
Clear: "rgb(192, 192, 192)",
}
Then to access the value it's just
skyGradients.Overcast // "linear-gradient(135deg, #808080, #404040)"
skyGradients["Overcast"] // "linear-gradient(135deg, #808080, #404040)"
skyGradients["someString"] // undefined
See other solutions below.
Since you're ok with undefined being returned when the key does not exist, you can safely cast the enum to any
.
export function getGradients(text: string): string | undefined {
return (SkyGradients as any)[text];
}
Although you open yourself to runtime errors if you ever add values to the enum that aren't strings.
You can get more robust type safety if you declare objects instead of enums (enums are just compiled down to objects anyway). You can typecast the object to still infer the object's type, but also allow indexing with arbitrary strings. You can even create a type to act like an enum type.
This eliminates the need for a getter function while maintaining strict type safety and the same functionality as enums. Albeit it's not pretty to look at.
const _skyGradients = {
Overcast: "linear-gradient(135deg, #808080, #404040)",
Clear: "linear-gradient(135deg, #C0C0C0, #808080)",
} as const;
export type SkyGradients = typeof _skyGradients[keyof typeof _skyGradients];
export const skyGradients = _skyGradients as typeof _skyGradients & {[key: string]: SkyGradients | undefined}
Example usage:
const test1 = skyGradients.Overcast // type is "linear-gradient(135deg, #808080, #404040)"
const test2 = skyGradients.Clear // type is "linear-gradient(135deg, #C0C0C0, #808080)"
const test3 = skyGradients["someString"] // type is SkyGradients | undefined
function someFn(g: SkyGradients) {}
someFn(skyGradients.Overcast) // Ok
someFn("someString") // Not Ok