Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve resolveConfig return type: merge themes #12272

Merged
merged 13 commits into from
Oct 27, 2023
Merged
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Fallback to RegEx based parser when using custom transformers or extractors ([#11335](https://github.com/tailwindlabs/tailwindcss/pull/11335))
- Bump `lightningcss` and reflect related improvements in tests ([#11550](https://github.com/tailwindlabs/tailwindcss/pull/11550))
- Fix incorrect spaces around `-` in `calc()` expression ([#12283](https://github.com/tailwindlabs/tailwindcss/pull/12283))
- Improve types for `resolveConfig` ([#12272](https://github.com/tailwindlabs/tailwindcss/pull/12272))

### Added

Expand Down
25 changes: 22 additions & 3 deletions resolveConfig.d.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,30 @@
import type { Config, ResolvableTo } from './types/config'
import { Config, ResolvableTo, ThemeConfig } from './types/config'
import { DefaultTheme } from './types/generated/default-theme'
import { DefaultColors } from './types/generated/colors'

type ResolvedConfig<T extends Config> = Omit<T, 'theme'> & {
theme: MergeThemes<
UnwrapResolvables<Omit<T['theme'], 'extend'>>,
T['theme'] extends { extend: infer TExtend } ? UnwrapResolvables<TExtend> : {}
>
}

type UnwrapResolvables<T> = {
[K in keyof T]: T[K] extends ResolvableTo<infer R> ? R : T[K]
}

type ResolvedConfig<T extends Config> = Omit<T, 'theme'> & {
theme: UnwrapResolvables<T['theme']>
type ThemeConfigResolved = UnwrapResolvables<ThemeConfig>
type DefaultThemeFull = DefaultTheme & { colors: DefaultColors }

type MergeThemes<Overrides extends object, Extensions extends object> = {
[K in keyof ThemeConfigResolved | keyof Overrides]: (K extends keyof Overrides
? Overrides[K]
: K extends keyof DefaultThemeFull
? DefaultThemeFull[K]
: K extends keyof ThemeConfigResolved
? ThemeConfigResolved[K]
: never) &
(K extends keyof Extensions ? Extensions[K] : {})
}

declare function resolveConfig<T extends Config>(config: T): ResolvedConfig<T>
Expand Down
3 changes: 1 addition & 2 deletions scripts/generate-types.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,9 +91,8 @@ fs.writeFileSync(
path.join(process.cwd(), 'types', 'generated', 'default-theme.d.ts'),
prettier.format(
`
import { Config } from '../../types'
type CSSDeclarationList = Record<string, string>
export type DefaultTheme = Config['theme'] & { ${defaultThemeTypes} }
export type DefaultTheme = { ${defaultThemeTypes} }
`,
{
semi: false,
Expand Down
7 changes: 4 additions & 3 deletions types/config.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ type Screen = { raw: string } | { min: string } | { max: string } | { min: strin
type ScreensConfig = string[] | KeyValuePair<string, string | Screen | Screen[]>

// Theme related config
interface ThemeConfig {
export interface ThemeConfig {
// Responsiveness
screens: ResolvableTo<ScreensConfig>
supports: ResolvableTo<Record<string, string>>
Expand Down Expand Up @@ -235,8 +235,9 @@ interface ThemeConfig {
transitionDuration: ResolvableTo<KeyValuePair>
willChange: ResolvableTo<KeyValuePair>
content: ResolvableTo<KeyValuePair>
}

// Custom
interface CustomThemeConfig extends ThemeConfig {
[key: string]: any
}

Expand Down Expand Up @@ -361,7 +362,7 @@ interface OptionalConfig {
future: Partial<FutureConfig>
experimental: Partial<ExperimentalConfig>
darkMode: Partial<DarkModeConfig>
theme: Partial<ThemeConfig & { extend: Partial<ThemeConfig> }>
theme: Partial<CustomThemeConfig & { extend: Partial<CustomThemeConfig> }>
corePlugins: Partial<CorePluginsConfig>
plugins: Partial<PluginsConfig>
// Custom
Expand Down