Search code examples
typescriptsolid-js

How to extend an interface with another interface depending on a property's type?


I want to be able to add additional constraints/types to my interface when a union type property is a particular value. Is this possible in Typescript?

So as a concrete example... If I have a type TypographyProps and it has a variant property in it of a union type. How can I use that variant property to extend the TypographyProps to include another type?

export interface TypographyProps extends ParentProps {
  variant?: "h1" | "h2" | "h3" | "p" | "span";
  color?: keyof Theme["colors"];
  spacing?: Theme["spacing"];
  wrap?: boolean;
}

// How can I add in the type def for each type `JSX.IntrinsicElements["h2"]`, etc... based on `variant`?

Solution

  • I ended up going with this solution. It is very similar to Tushar Shahi's answer above but I needed to be more explicit with strings in each type rather than create a new Variant type that has everything.

    type HeadingVariantProps = {
      variant: "heading" | "subheading" | "title" | "subtitle";
      ref?: Ref<HTMLHeadingElement>;
    };
    
    type BodyVariantProps = {
      variant: "body";
      ref?: Ref<HTMLParagraphElement>;
    };
    
    type DefaultVariantProps = {
      variant?: undefined;
      ref?: Ref<HTMLSpanElement>;
    };
    
    export type TypographyProps = ParentProps & {
      color?: keyof Theme["colors"];
      spacing?: Theme["spacing"];
      wrap?: boolean;
    } & (HeadingVariantProps | BodyVariantProps | DefaultVariantProps);