Search code examples
reactjstypescript

How to create a typescript type that validates string format? i.e. checks is string is valid css length property


So I have a react project where the component takes a height prop. That prop is used to determine the css properties for the component (I use the emotion library)

For example,

render() {
  const styles = css`
    height: ${this.props.height};
  `;

  return (
    <div style={styles}>
      ...
    </div>
  );
}

I have a type for height, which is currently

interface Props {
  height: number | string;
}

Instead of having a type that checks if the height is a string, I want to create a type that validates the unit of height if it is a string.

For example,

10px is a valid prop, so no typescript error.

10xp will throw a typescript error.

Is there a way to create a type that checks that the first part is a number, and the second part is one of these values?

type CssAbsoluteUnit = "cm" | "mm" | "in" | "px" | "pt" | "pc";

type CssRelativeUnit = "em" | "ex" | "ch" | "rem" | "vw" | "vh" | "vmin" | "vmax" | "%";

I'd like to do this in a way that typescript compiler will throw an error, so using just regex to validate on render doesn't really do the job.


Solution

  • Unfortunately, this sounds like something that is determined during runtime after the compiler has done it's job. However, if you know ahead of time, what values that are going to be passed you can create an interface and implement the classes for the types that are going to be passed in.

    Something like this:

    interface CssUnit {
      getValue(): string;
    }
    
    class PxUnit implements CssUnit {
      private unit: string;
    
      constructor(value: number) {
        this.unit = value + "px";
      }
    
      getValue(): string {
        return this.unit;
      }
    }
    

    then,

    interface Props {
      height: CssUnit;
    }
    

    All you would have do to is pass in one of your implemented classes.

    Hope that helps!