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

Improve resolveConfig return type: merge themes #12272

merged 13 commits into from
Oct 27, 2023

Conversation

baffalop
Copy link
Contributor

@baffalop baffalop commented Oct 23, 2023

This PR addresses #12264, adding some special handling of the theme key in ResolvedConfig to better reflect how theme and theme.extend are merged with the default theme values. Specifically:

  • Include the generated type DefaultTheme in the return value
  • If a theme key is set in config.theme, it overrides the default theme value
  • If a theme key is extended in config.theme.extend, it's intersected with the resolved theme value
  • Custom theme keys set in the user config will also still show up in the return type

The generated DefaultTheme type doesn't itself contain all possible theme config keys (those that are defined via a callback are omitted), so we fall back to values from ThemeConfig, which are of a less concrete type (eg. KeyValuePair<string, string>).

Basically, I think I've implemented the "ridiculousness with conditional types" mentioned in the review for this PR

Incidental changes

A couple of small changes were necessary elsewhere in the codebase to facilitate this:

generate-types.js: Do not intersect the generated DefaultTheme type with Config['theme']. We need to use the concrete value types in here to improve the ResolvedConfig type, and the Config['theme'] types get in the way of this. As far as I can see, the only place where DefaultTheme is currently referenced is in defaultTheme.d.ts where it is once again intersected with Config['theme'], so this change shouldn't make a difference to that.

config.d.ts: I exported ThemeConfig to use in ResolvedConfig, and I also split out a separate ThemeConfigCustomizable interface which includes the final [key: string]: any. Otherwise there was no way to avoid ResolvedConfig itself including a fallback [key: string]: any, rendering any unknown property access valid in typescript's eye.

Testing

Given that the codebase itself isn't written in typescript, I wasn't sure of a good way to test the changes. I resorted to creating a sample ts file defining a config, resolving it, and trying to access various keys on the output---using my IDE for typescript feedback.

Example test file
import { Config } from './types/config'
import resolveConfig = require('./resolveConfig')

const config = {
  content: ['**/*.js'],
  theme: {
    gap: {
      1: '1',
      2: '2',
    },
    myCustom: {
      foo: 'custom',
      bar: 'custom',
    },
    extend: {
      colors: {
        cerulean: {
          50: 'bla',
          100: 'yeah',
          200: 'another',
        }
      },
      gap: {
        3: '3'
      }
    }
  }
} satisfies Config

const theme = resolveConfig(config).theme

theme.colors.cerulean // ✅
theme.colors.zinc // ✅
theme.gap // { 1, 2, 3 }
theme.spacing // { 0, 1, 2, 3, ... }
theme.padding // KeyValuePair<string, string>
// @ts-expect-error
theme.extend
// @ts-expect-error
theme.bla
theme.myCustom // ✅

I'd gladly do more real-world testing or add tests to the codebase if an approach could be suggested.

This is my first PR to a large-scale OS project. I hope it's useful!

@baffalop
Copy link
Contributor Author

I'm used to using Gitlab which gives an option to squash commits when merging an MR. Is there no do the same in Gitlab? Please let me know if I should squash my commits on the branch itself.

@RobinMalfait RobinMalfait self-assigned this Oct 24, 2023
@RobinMalfait RobinMalfait merged commit 02da2b8 into tailwindlabs:master Oct 27, 2023
10 checks passed
@RobinMalfait
Copy link
Contributor

Hey!

While this isn't 100% correct yet, it is still more correct than it was before. GitHub isn't showing it properly, but I rebased this PR to have the latest changes from master as well. You are still the author on most of the commits:
image

I added 2 commits to:

  • Fix the TypeScript warning when trying to use T['theme']['extend']
  • To format the types using Prettier

Regarding your comment about squashing, that's something maintainers can choose when merging. Contributors can't choose this. We always "Squash and merge" so you don't have to do anything.

image

Thanks for the PR!

@baffalop
Copy link
Contributor Author

That's great, thank you @RobinMalfait ! I'm not particularly precious about getting the credit, but good to know—it was a bit weird that Github started showing all my commits as yours. I agree with your changes. I had forgotten prettier was to be used for formatting, I was expecting eslint to say something but it was falling over parsing typescript.

And yes, the return type isn't perfect but it's much better. I had actually meant to write up the caveats. Maybe I'll add them into the PR description for posterity.

thecrypticace pushed a commit that referenced this pull request Oct 30, 2023
* 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 <ngaidakov@podfather.com>
Co-authored-by: Robin Malfait <malfait.robin@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants