glo
glo

Reputation: 799

use of the "in" type guard in typescript

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

Answers (1)

Nick Vu
Nick Vu

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;
}

Playground

Upvotes: 1

Related Questions