styled-components / xstyled

A utility-first CSS-in-JS framework built for React. 💅👩‍🎤⚡️
https://xstyled.dev
MIT License
2.27k stars 106 forks source link

Enhanced theme value acquisition for "th" helper #308

Closed quantizor closed 2 years ago

quantizor commented 2 years ago

Using newer techniques in TS 4.1 we can acquire an exact list of string paths for helpers like th.color.

For example, this TS type helper:

type PropsPath<T extends Theme> = {
  [P in keyof T]: T[P] extends Theme
    ? `${string & P}` | `${string & P}.${PropsPath<T[P]>}`
    : `${string & P}`;
}[T extends any[] ? number & keyof T : keyof T];

Can be used to extract theme values from a type:

const theme = {
  colors: {
    green: '#2B968F',
    modes: {
      dark: {
        green: '#55B9AD',
      }
    }
  }
} as const

type ThemeColors = PropsPath<typeof theme['colors']>
// -> 'green' | 'modes.dark.green'

And then can be used in the th.color helper for example:

type PropsPath<T extends Theme> = {
  [P in keyof T]: T[P] extends Theme
    ? `${string & P}` | `${string & P}.${PropsPath<T[P]>}`
    : `${string & P}`;
}[T extends any[] ? number & keyof T : keyof T];

interface Th {
  color(themeColor: PropsPath<ITheme['colors']>): string
}
gregberge commented 2 years ago

@probablyup yeah you are right, we can now improve typings. When I switch the library on TypeScript it was just released, I didn't wanted to rely on it. But now it is possible!

quantizor commented 1 year ago

@gregberge I saw this article recently, might have better perf compared to the previous solution: https://javascript.plainenglish.io/advanced-typescript-type-level-nested-object-paths-7f3d8901f29a

It specifically mentions handling recursion better which is why the previous one was backed out I think