skip to Main Content

I have the following code:

<Show when={!!icon} fallback={<SVG src={defaultIcon}/>}>
     <SVG src={icon!} className={styles.buttonIcon} />
</Show>

Because icon can be undefined, I created a wrapper to wrap SVG component with, but typescript still thinks that icon can be undefined even if the only way for it to appear is if icon is defined. Is there a way to tell typescript that when icon is used inside the Show wrapper it will be defined?

I know that

<SVG src={icon ?? defaultIcon} className={styles.buttonIcon} />

is "better" for that situation but there are some more complicated situations that I would like to use this custom made Show wrapper

2

Answers


  1. You can try

    { icon && <SVG src={icon} className={styles.buttonIcon} /> }
    

    Or

    { icon ? <SVG src={icon} className={styles.buttonIcon} /> : <SVG src={defaultIcon}/>  }
    
    Login or Signup to reply.
  2. Like you mentioned in simple cases you can rely on TypeScript’s implicit type narrowing but in more complex cases when you extract the conditional you lose the implicit type narrowing. The solution is to explicitly narrow types. Here’s a quick draft of what a type safe version of your conditional component might look like:

    const When = <P extends Record<string, unknown>, T extends P>({
      props,
      predicate,
      component: Component,
      fallback: Fallback,
    }: {
      props: P;
      predicate: (props: P) => props is T;
      component: React.ComponentType<T>;
      fallback: React.ComponentType<P>;
    }) => (predicate(props) ? <Component {...props} /> : <Fallback {...props} />);
    

    Usage is a bit verbose but you can extract each prop value into its own function:

    <When
      props={{ src: icon, className: styles.buttonIcon }}
      predicate={<T extends { src: string | null | undefined }>(
        props: T
      ): props is T & { src: string } => props.src != null}
      component={SVG}
      fallback={() => <SVG src={defaultIcon} />}
    />
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search