Reputation: 799
I am trying to create a type guard - to allow typesafe conversion of a series of shorthand css properties, to their longhand version - but do so without having to cast the rule back to keyof SxProps
at the end.
type SxProps = { w?: string; width?: string; h?: string; height?: string; }
const shorthandCssRuleMapping = {
w: 'width',
h: 'height'
} as const;
export function hasKey<K extends string>(
key: K,
object: {}
): object is { [_ in K]: {} } {
return typeof object === "object" && object !== null && key in object;
}
export function convertShorthandRule(rule: keyof SxProps) {
let longHandRule = rule;
if (hasKey(rule, shorthandCssRuleMapping)) {
let pickedShortHandRule = shorthandCssRuleMapping[rule];
// @NOTE: REALLY wish we didn't have to cast here...
longHandRule = pickedShortHandRule as keyof SxProps;
}
return longHandRule;
}
basically, the type of pickedShorthandRule is this: {} | "width" | "height"
before we cast it. Im pretty sure this is from a dodgy type predicate - but cant work out how to fix it. :P
I really need it to be: "width" | "height"
- so that I can get rid of the cast: as keyof SxProps
Help!
Upvotes: 0
Views: 213
Reputation: 15520
You can change object is { [_ in K]: {} }
to object is { [_ in K]: keyof SxProps }
to make sure the values in shorthandCssRuleMapping
will be always from long-hand keys
type SxProps = { w?: string; width?: string; h?: string; height?: string; }
const shorthandCssRuleMapping = {
w: 'width',
h: 'height'
} as const;
export function hasKey<K extends string>(
key: K,
object: {}
): object is { [_ in K]: keyof SxProps } {
return typeof object === "object" && object !== null && key in object;
}
export function convertShorthandRule(rule: keyof SxProps) {
let longHandRule = rule;
if (hasKey(rule, shorthandCssRuleMapping)) {
let pickedShortHandRule = shorthandCssRuleMapping[rule];
longHandRule = pickedShortHandRule;
}
return longHandRule;
}
Upvotes: 1