Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Is it possible to limit the formatting of a string in Typescript (or ESLint?)

I’m working in a codebase using React (CRA) and TypeScript. We’ve got the typical settings with a few linters and our own Design System.

Recently, we updated the Design System with CSS in JS, to allow the use of props like width="125px" on any components coming from it. We also introduced a Sizing and Spacing scales, which allows to use width={8} (for example).

While we’re trying our best to share the knowledge within the company, I’m seeing some code changes including changes like width="8" (it does make sense that if you’re not used to it, a number as prop will usually be set as a string, and you would keep the {} only for actual variables and objects). This still works and outputs the right value in the HTML, but it takes away the validation within the editor (width={30} would be out of our scale and the dev would be notified, width="30" is just a string so we’re not checking it).

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

So TLDR, my question is: Is it possible to type check more aggressively but also in a smart way. My goal would be to:

  • Allow: {10} "10px" "10rem" "10%" "inherit" etc.
  • Deny: "10"
  • Allow "10" on other props like line-height or font-weight (typed separately so I don’t even think this needs to be changed)

Right now, if I take width for example, the typing is using our own scale going from {1} to {18}:

  export type Width<TLength = (string & {}) | 0> =
| Globals
| TLength
| "-moz-fit-content"
| "-moz-max-content"
| "-moz-min-content"
| "-webkit-fit-content"
| "-webkit-max-content"
| "auto"
| "fit-content"
| "intrinsic"
| "max-content"
| "min-content"
| "min-intrinsic"
| (string & {});

>Solution :

You can use Template Literal Types (tsc >=4.1)

type Nums = 1 | 2 | 3;

type Unit = "px" | "em" | "%";
type NumWithUnit = `${number}${Unit}`

type Width = Nums | NumWithUnit | "inherit"

const passes: Width[] = [
  1, 2, 3,
  "10px",
  "1.5em",
  "50%",
  "inherit"
]

const fails: Width[] = [
  // @ts-expect-error
  4,
  // @ts-expect-error
  "10",
  // @ts-expect-error
  "x em"
]

Playground

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading