From ffadf2ba4b55c844106067aea8ca62aafebf8f67 Mon Sep 17 00:00:00 2001 From: Nikita Gaidakov <33629446+baffalop@users.noreply.github.com> Date: Fri, 27 Oct 2023 14:46:02 +0100 Subject: [PATCH] Improve resolveConfig return type: merge themes (#12272) * Generate types: do not intersect with Config theme type when generating DefaultTheme * Merge default theme in ResolvedConfig * UnwrapResolvables on theme.extend as well * Apply extend to overrides and default theme * Omit extend from DefaultTheme * Relax generic constraints, better generic variable names * Fall back to ThemeConfig if key not in DefaultTheme * Split out ThemeConfigCustomizable to avoid anys in ThemeConfigResolved * Allow custom theme properties * handle TypeScript error * apply prettier formatting * update changelog * change type name --------- Co-authored-by: Nikita Gaidakov Co-authored-by: Robin Malfait --- CHANGELOG.md | 1 + resolveConfig.d.ts | 25 ++++++++++++++++++++++--- scripts/generate-types.js | 3 +-- types/config.d.ts | 7 ++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b8d4590a..081e64db5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Don’t add spaces to negative numbers following a comma ([#12324](https://github.com/tailwindlabs/tailwindcss/pull/12324)) - Don't emit `@config` in CSS when watching via the CLI ([#12327](https://github.com/tailwindlabs/tailwindcss/pull/12327)) +- Improve types for `resolveConfig` ([#12272](https://github.com/tailwindlabs/tailwindcss/pull/12272)) ## [3.3.5] - 2023-10-25 diff --git a/resolveConfig.d.ts b/resolveConfig.d.ts index 2402a267e..792162775 100644 --- a/resolveConfig.d.ts +++ b/resolveConfig.d.ts @@ -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 = Omit & { + theme: MergeThemes< + UnwrapResolvables>, + T['theme'] extends { extend: infer TExtend } ? UnwrapResolvables : {} + > +} type UnwrapResolvables = { [K in keyof T]: T[K] extends ResolvableTo ? R : T[K] } -type ResolvedConfig = Omit & { - theme: UnwrapResolvables +type ThemeConfigResolved = UnwrapResolvables +type DefaultThemeFull = DefaultTheme & { colors: DefaultColors } + +type MergeThemes = { + [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(config: T): ResolvedConfig diff --git a/scripts/generate-types.js b/scripts/generate-types.js index d3e0d303e..a0bd5d523 100644 --- a/scripts/generate-types.js +++ b/scripts/generate-types.js @@ -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 - export type DefaultTheme = Config['theme'] & { ${defaultThemeTypes} } + export type DefaultTheme = { ${defaultThemeTypes} } `, { semi: false, diff --git a/types/config.d.ts b/types/config.d.ts index 6d171ceed..b5d9ddc80 100644 --- a/types/config.d.ts +++ b/types/config.d.ts @@ -79,7 +79,7 @@ type Screen = { raw: string } | { min: string } | { max: string } | { min: strin type ScreensConfig = string[] | KeyValuePair // Theme related config -interface ThemeConfig { +export interface ThemeConfig { // Responsiveness screens: ResolvableTo supports: ResolvableTo> @@ -234,8 +234,9 @@ interface ThemeConfig { transitionDuration: ResolvableTo willChange: ResolvableTo content: ResolvableTo +} - // Custom +interface CustomThemeConfig extends ThemeConfig { [key: string]: any } @@ -358,7 +359,7 @@ interface OptionalConfig { future: Partial experimental: Partial darkMode: Partial - theme: Partial }> + theme: Partial }> corePlugins: Partial plugins: Partial // Custom