Skip to content

Commit 8d611e0

Browse files
committed
WIP: theme() utility function code completion
This will give you code completion in the `theme()` function. The reason it is still a WIP is that this only works with the default config right now and not 100% sure if it is possible to define generics in JSDoc. The idea would be to: - Provide types from the default config - Provide types from the custom config (e.g.: 3rd party plugin) - Override default config types with the overrides of the user's config Right now this only provides types for the defaultConfig which might result in dropping all of this in favor of a much simpler: ```ts theme<D = any>(path: string, defaultValue: D) => D ``` But this sadly doesn't give you "nice" auto completion. However, the default might be good enough if we don't error on for example `theme('customPlugin')` which is currently not the case.
1 parent be95f7a commit 8d611e0

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

types/config.d.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,53 @@ interface RecursiveKeyValuePair<K extends keyof any = string, V = string> {
1313
}
1414
type ResolvableTo<T> = T | ((utils: PluginUtils) => T)
1515

16+
type DotNotation<T, K extends keyof T = keyof T> = K extends string
17+
? T[K] extends Record<string, any>
18+
? T[K] extends any[]
19+
? K | `${K}.${DotNotation<T[K], Exclude<keyof T[K], keyof any[]>>}`
20+
: K | `${K}.${DotNotation<T[K], keyof T[K]>}`
21+
: K
22+
: never
23+
type Path<T> = DotNotation<T> | keyof T
24+
type PathValue<T, P extends Path<T>> = P extends `${infer K}.${infer Rest}`
25+
? K extends keyof T
26+
? Rest extends Path<T[K]>
27+
? PathValue<T[K], Rest>
28+
: never
29+
: never
30+
: P extends keyof T
31+
? T[P]
32+
: never
33+
34+
// Removes arbitrary values like: { [key: string]: any }
35+
type WithoutStringKey<T> = { [K in keyof T as string extends K ? never : K]: T[K] }
36+
37+
type Unpack<T> = T extends ResolvableTo<infer R>
38+
? { [K in keyof R]: Unpack<R[K]> }
39+
: T extends object
40+
? { [K in keyof T]: Unpack<T[K]> }
41+
: T
42+
43+
// This will remove all the callbacks and simplify it to the actual object
44+
// it uses or the object it returns. It will also remove the `extend`
45+
// section because at runtime that's gone anyway.
46+
type UnpackedTheme = Omit<WithoutStringKey<Unpack<Config['theme']>>, 'extend'>
47+
48+
// This will add additional information purely for code completion. E.g.:
49+
type AugmentedTheme = Expand<Omit<UnpackedTheme, 'colors'> & { colors: DefaultColors }>
50+
1651
interface PluginUtils {
1752
colors: DefaultColors
18-
theme(path: string, defaultValue: unknown): keyof ThemeConfig
53+
54+
// Dynamic based on (default) theme config
55+
theme<P extends Path<AugmentedTheme>, TDefaultValue>(
56+
path: P,
57+
defaultValue?: TDefaultValue
58+
): PathValue<AugmentedTheme, P>
59+
// Path is just a string, useful for third party plugins where we don't
60+
// know the resulting type without generics.
61+
theme<TDefaultValue = any>(path: string, defaultValue?: TDefaultValue): TDefaultValue
62+
1963
breakpoints<I = Record<string, unknown>, O = I>(arg: I): O
2064
rgb(arg: string): (arg: Partial<{ opacityVariable: string; opacityValue: number }>) => string
2165
hsl(arg: string): (arg: Partial<{ opacityVariable: string; opacityValue: number }>) => string

0 commit comments

Comments
 (0)