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

Updated types to support global Theme definition #1609

Merged
merged 19 commits into from
Dec 7, 2019

Conversation

tomsseisums
Copy link
Contributor

@tomsseisums tomsseisums commented Nov 5, 2019

What:
Fixes #1197

Why:
The current typings do not support a way of providing theme types globally. The re-exports can only go so far, and the styled themed re-export actually tampers with babel plugin.

How:
I added Theme export via a global namespace as suggested by @JakeGinnivan so that it can be overriden with:

// emotion-theme.d.ts
declare global {
  namespace Emotion {
    export interface Theme {
      your: 'theme',
      comes: 'here'
    }
  }
}

And updated all usages of previous default any to use the namespace one.

Checklist:

  • Documentation
  • Tests
  • Code complete
  • Changeset

I don't know how to add test cases for this.
I tried by adding a globalTests.tsx containing actual tests and emotion-theme.d.ts containing the declaration alongside the respective tests. But all my efforts to prevent emotion-theme.d.ts global declaration from bleeding into un-overriden usecase tests failed. If the global theme declaration bleeds into un-overriden usecase tests, it breaks the tests there. Probably for the same reasons as can be seen in styled-components typings:

/**
 * This interface can be augmented by users to add types to `styled-components`' default theme
 * without needing to reexport `ThemedStyledComponentsModule`.
 */
// Unfortunately, there is no way to write tests for this
// as any augmentation will break the tests for the default case (not augmented).
// tslint:disable-next-line:no-empty-interface
export interface DefaultTheme {}

I'm opening this as a draft because I lack documentation/changeset, and want some initial reviews.
Updated to ready, because... how would one review it otherwise?

Also, what does Code complete mean in the checklist?

@changeset-bot
Copy link

changeset-bot bot commented Nov 5, 2019

🦋 Changeset is good to go

Latest commit: f391e6c

We got this.

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@tomsseisums tomsseisums marked this pull request as ready for review November 5, 2019 21:05
@JakeGinnivan
Copy link
Contributor

More general question.

Why don't we just remove the Theme generic parameter from everywhere and just reference Emotion.Theme or the module version directly?

It would remove a heap of generic params and complexity from the types?

@JakeGinnivan
Copy link
Contributor

Nice work getting the ball rolling on this, I think this will be an awesome change. I had a go at just removing the generic params for theme from everywhere?

Thoughts:

tomsseisums#1

Also, for compat we could just use documentation to fill the gap (I thought I posted this somewhere, but can't find it. Oh well).

declare global {
  export interface Theme extends Record<string, any> {
  }
}

@JakeGinnivan
Copy link
Contributor

After doing the above, I wonder if there is much value in the emotion-theming package at all.

IMO v11 could completely remove it, you just move the ThemeProvider, hook and HoC into core?

@emmatown
Copy link
Member

I'm good with moving the theming APIs to core. @Andarist want to create a PR?

@Andarist
Copy link
Member

@mitchellhamilton sure, gonna handle this today.

@Andarist
Copy link
Member

@joltmode I've just merged in the PR which has moved theming APIs into @emotion/core. Could you rebase this branch and incorporate suggestions from tomsseisums#1 ?

@Andarist
Copy link
Member

@joltmode will you be able to work on this in the near future? If not - that's perfectly fine, we'd only appreciate a heads up so somebody could take over this.

@tomsseisums
Copy link
Contributor Author

@Andarist yes, will strive to push this forward during the weekend.

@codesandbox-ci
Copy link

codesandbox-ci bot commented Nov 23, 2019

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

Latest deployment of this branch, based on commit f391e6c:

Sandbox Source
Emotion Configuration

@Andarist
Copy link
Member

Looking quite good!

As discussed briefly before - if it's possible we'd prefer to keep that Emotion.Theme as part of the @emotion/core module - rather than in the global namespace.

@tomsseisums
Copy link
Contributor Author

Yup, looking to update that one.

Currently working on fixing tests, forgot to run before pushing.

Was a pretty nasty rebasing, loads of changes inbetween! Quite possibly this was the toughest merge conflict in my development life so far. 🥇

@@ -248,34 +248,33 @@ const App = () => (
### Define a Theme
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The whole docs on Theme usage with TS feels massively outdated now, and I feel like it should be reworded altogether.

Exposing for discussion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right - I feel like we can handle it in a separate PR though. Ideally, such docs would present the current solution with its tradeoffs and incorporate stuff from this #973

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's not in this PR, it should definitely be a blocker for releasing v11.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is crucial and I plan to get this done before v11 👍

(mergedProps: MergedProps): Interpolation<MergedProps>
}

export type Interpolation<MergedProps = undefined> =
export type Interpolation<MergedProps = { theme: Theme }> =
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually I think that Interpolation is also used in css definition and in there you don't have access to Theme, so the previous version with default being undefined was correct for css's case

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this and the serializeStyles stuff should be better viewed by @JakeGinnivan. Not on the same train of thought as he is on with these.

I also invited you @JakeGinnivan as a member to my repo, so it's not mandatory to have to PR.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda backed away from these types during my initial work. I wonder if we should just not have a default? (then if not specified it will be unknown)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css definition and in there you don't have access to Theme

Just for my understanding, why is this the case? Looking at the other types elsewhere we could actually do another round of simplification if we could add theme into these types directly

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css definition and in there you don't have access to Theme

Just for my understanding, why is this the case?

I've meant css function - you can't do css(() => /**/). From what remember such function just gets stringified. css call is being executed without any notion of context, you can hoist it wherever you want etc - so it has no access to theme or props.

A different story is the css props - where you can get access to the builtin Theme.

Looking at the other types elsewhere we could actually do another round of simplification if we could add theme into these types directly

What kind of simplification do you have in mind? I've noticed now that we have Interpolation, CSSInterpolation and even InterpolationWithTheme and I think they might be used sometimes in wrong contexts (especially the Interpolation type). I need to draw out the dependency tree of those types somewhere for myself to analyze this further 😅

@@ -79,7 +83,7 @@ export type Interpolation<MergedProps = undefined> =
| ObjectInterpolation<MergedProps>
| FunctionInterpolation<MergedProps>

export function serializeStyles<MP>(
export function serializeStyles<MP = { theme: Theme }>(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here - serializeStyles gets called by css

@Andarist
Copy link
Member

@JakeGinnivan would appreciate you taking a look at this as well

@@ -248,34 +248,33 @@ const App = () => (
### Define a Theme
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's not in this PR, it should definitely be a blocker for releasing v11.

docs/typescript.mdx Outdated Show resolved Hide resolved
(mergedProps: MergedProps): Interpolation<MergedProps>
}

export type Interpolation<MergedProps = undefined> =
export type Interpolation<MergedProps = { theme: Theme }> =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I kinda backed away from these types during my initial work. I wonder if we should just not have a default? (then if not specified it will be unknown)

ComponentProps &
SpecificComponentProps &
StyleProps &
AdditionalProps & { theme: Theme }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the union with theme needed here? I think the entrypoint (the styled function) adds theme?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{ theme: Theme } gets always passed in as StyleProps, so we should be able to remove this from here, but when I try to do that then I get such errors:

Error: /emotion/packages/styled/types/tests-base.tsx:156:32
ERROR: 156:32  expect  TypeScript@next compile error: 
Object is possibly 'undefined'.

/emotion/packages/styled/types/tests.tsx:19:7
ERROR: 19:7    expect  Expected type to be:
  { theme?: Theme | undefined; } & ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement> & { bar: string; } & { theme: Theme; }
got:
  { theme?: Theme | undefined; } & ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement> & { bar: string; }

Still investigating this, but right now I don't see why this fails.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While I don't understand why this fails - it might actually be a proper thing to specify this here instead of passing it from the above level in StyleProps. After all - theme is always available in interpolations, so it shouldn't be possible to "cancel" it out by passing StyleProps without it?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok - I know why this thing has been failing:
https://github.com/joltmode/emotion/blob/464922628c9197988ac7ae38d33b84b6eb6d63d8/packages/styled/types/base.d.ts#L89-L93
This doesn't include StyleProps. It should right?

Regardless of that - my previous question stands. Should we pass Theme as part of StyleProps from the above or should we just pass it directly to Interpolation?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I've decided to move { theme: Theme } inline where parameters are being passed to Interpolation inside styled components. Seems the most appropriate solution - but I'm happy to discuss this further, maybe I've missed something?

More than that - I'm right now kinda questioning if we need StyleProps at all, what do you think?

(mergedProps: MergedProps): Interpolation<MergedProps>
}

export type Interpolation<MergedProps = undefined> =
export type Interpolation<MergedProps = { theme: Theme }> =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

css definition and in there you don't have access to Theme

Just for my understanding, why is this the case? Looking at the other types elsewhere we could actually do another round of simplification if we could add theme into these types directly

@Andarist Andarist merged commit c643107 into emotion-js:next Dec 7, 2019
@Andarist Andarist deleted the topics/global-theme-type branch December 7, 2019 21:03
@stramel
Copy link

stramel commented Dec 20, 2019

@Andarist I'm not sure if this is causing a problem or if it's just misleading.

I noticed it seems to be pulling a test base typing instead the interface from the main library.

image

@Andarist
Copy link
Member

Interesting, could you prepare a runnable repro case (a simple repository)? That would help me a lot to jump into investigating this. It might be also worth reporting an issue about this. Notice though that main library typing is picked up correctly (you can see that on the right of your screenshot - first item on the list is the one from the main library), the problem is though that the test typings are also picked up.

@stramel
Copy link

stramel commented Dec 21, 2019

I will do my best to create a repo

@JakeGinnivan
Copy link
Contributor

I wonder if we should just not include the test files @Andarist?

Something like this
image

@Andarist
Copy link
Member

Yeah, that would be the simplest fix. Prepared a PR for that - #1702

louisgv pushed a commit to louisgv/emotion that referenced this pull request Sep 6, 2020
…ed by consumers (emotion-js#1609)

* Updated types to support global Theme definition

* Updated documentation to reflect new theme typings

* Simplified MuiTheme import syntax in docs

* Use previous theme declaration in docs

- [side-effect] Updated back to 2 space indentation

* Update Button.tsx import declaration for styled

* Updated type definitions to default to any if not defined

* Quick pass at removing theme generic param

* Fixed issue with Global

* Fixed most of the test issues

- Added TODO for one possible issue

* Updated global Theme type declaration to module specific

* Removed exports from test files

* Use the incomplete theme prop testcase

- Add test case for fully overriding theme

* Added note about where styled tests get their theme declaration from

* tweak docs

* Remove InterpolationWithTheme type

* Move adding Theme to Styled interpolations inline (and not as part of StyleProps)

* Cleanup Interpolation-related types

* Add changeset
@github-actions github-actions bot mentioned this pull request Nov 10, 2020
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

5 participants