frenic / csstype

Strict TypeScript and Flow types for style based on MDN data
MIT License
1.7k stars 69 forks source link

How to limit the StandardLonghandProperties[`propertyName`] type to valid strings? #166

Open bart-krakowski opened 1 year ago

bart-krakowski commented 1 year ago

I'd like to make sure the user will be able to provide only a valid strings to a component with this props:

interface ComponentProps {
  width?: StandardLonghandProperties["width"]
}

but it allows to provide any string or number:

<Component width="foo-bar" />

I've noticed that it could work when I remove | (string & {}); from this interface:

  export type Width<TLength = (string & {}) | 0> =
    | Globals
    | TLength <--- this might be string
    | "-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 & {}); <---

Now I'm able to pass 0 as a type param to the StandardLonghandProperties interface:

interface ComponentProps {
  width?: StandardLonghandProperties<0>["width"]
}

...

<Component width="foo-bar" /> // this fails
<Component width="auto" /> // this pass
<Component width="10px" /> // this fails

As a solution for the issue with px, rem etc I suggest using Template Literal Types:

    | `${number}${`px`|`em`|`rem`|`vw`|`vh`}`;
kylemh commented 1 year ago

It'd have to be:

type Unit = `${number}${`ch`|`em`|`px`|`rem`|`vh`|`vw`|`%`}`;
type CSSFunction = `${string}(--${string | number})`; // like `var(--some-var)` or `calc(100% - 220px)`

type StandardLonghandPropertiesValue = Unit | CSSFunction;

at least.

Can't think of other edge cases, but this sort of typing is tough... Even CSSFunction could be spoofed wrong.