When I have a type property that requires another property in the type to be a specific value, my types become overly complex. I'd like to write a utility type that abstracts the logic.
Example. Say I write a type that relates to a Text (React) component I'm building:
type Props = {
children: React.ReactNode; // Just a React type, not pertinent to the question
as: "p" | "span" | "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; // The html tag for the text
truncate?: boolean; // Whether to truncate the text when it is long
expanded?: boolean; // The truncated text is expanded when this is true
bigHeading?: boolean; // When `as` is `"h1" | "h2" | "h3" | "h4" | "h5" | "h6"`, this property makes a normal heading extra large.
}
expanded?
doesn’t do anything unless truncate?
is true
, and bigHeading?
doesn’t do anything unless as
is "h1" | "h2" | "h3" | "h4" | "h5" | "h6"
. So, I want the Props
type to disallow expanded
and bigHeading
unless those conditions are met.
The way I go about it is this:
type BaseProps = {
children: React.ReactNode;
};
type NoTruncateProps = BaseProps & {
as: "p" | "span";
truncate?: false;
};
type TruncateProps = BaseProps & {
as: "p" | "span";
truncate: true;
expanded?: boolean;
};
type NoTruncateHeadingProps = BaseProps & {
as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
bigHeading?: boolean;
truncate?: false;
};
type TruncateHeadingProps = BaseProps & {
as: "h1" | "h2" | "h3" | "h4" | "h5" | "h6";
bigHeading?: boolean;
truncate: true;
expanded?: boolean;
};
type Props = NoTruncateProps | TruncateProps | NoTruncateHeadingProps | TruncateHeadingProps
This is obviously overly complex. How would I simplify and abstract this logic away for re-usability?