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).
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 likeline-heightorfont-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"
]