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

Want TypeScript error for when css prop is passed a function (instead of SerializedStyles) #1447

Closed
WestonThayer opened this issue Jul 28, 2019 · 11 comments

Comments

@WestonThayer
Copy link

WestonThayer commented Jul 28, 2019

The problem

When using Emotion, I mostly create "static" styles in variables for use in my JSX to avoid cluttering the JSX with style information. For example:

const style = css({ fontSize: 40 });
const Component = () => <button css={style}>content</button>;

Occasionally I need to create "dynamic" styles, based off of the component's props:

const style = size => css({ fontSize: size });
const Component = props => <button css={style(props.size)}>content</button>;

A common mistake I make is forgetting to call style() as a function, and instead writing css={style}, which of course doesn't apply any styles because the style() function is never called.

I was hoping that using TypeScript with Emotion would help me avoid this error, but Emotion's typings for the css prop seem to allow the function. I wish the typings would warn me.

Here's an example: https://codesandbox.io/s/mystifying-keldysh-bdker

Proposed solution

Emotion's type definitions should cause a TypeScript error when I pass a function to the css prop.

@Andarist
Copy link
Member

That's because functions are supported as values of css prop, a function in that position gets called with theme as argument.

@WestonThayer WestonThayer changed the title Typescript error for when css prop is passed a function (instead of SerializedStyles) Want TypeScript error for when css prop is passed a function (instead of SerializedStyles) Jul 28, 2019
@WestonThayer
Copy link
Author

Ah thanks, I see that now. It would be awesome if I had the ability to specify the generic type. Right now, it’s hard coded to any. If I’m reading correctly, setting it to the type of my theme object would be ideal. That way functions that take the theme would be accepted, but functions for dynamic styles that accept some props would be rejected.

@Andarist
Copy link
Member

There is an ongoing effort to rework current type definitions in #1501 . I'd like to include feedback from #1507 and related issues as part of this work. I hope this will resolve your issue. Stay tuned!

@JakeGinnivan
Copy link
Contributor

@WestonThayer having a look at this, I can't think of a way to solve this off the top of my head.

Because it's an ambient type once the emotion library declares it I'm not sure how you would override them unfortunately.

@Andarist
Copy link
Member

After some thinking right now - if we would have to support declaration merging for DefaultTheme then this could have been "fixed".

@WestonThayer
Copy link
Author

I like the declaration merging solution. I just tested it out in an emotion fork. If @emotion/core/types/index.d.ts adds:

export interface DefaultTheme {}

...

declare module 'react' {
  interface DOMAttributes<T> {
    css?: InterpolationWithTheme<DefaultTheme>
  }
}

declare global {
  namespace JSX {
    interface IntrinsicAttributes {
      css?: InterpolationWithTheme<DefaultTheme>
    }
  }
}

Then out of the box, I get a really nice TS error when attempting to pass a dynamic style to css:

Type '(props: MyComponentProps) => SerializedStyles' is not assignable to type 'InterpolationWithTheme<DefaultTheme>'.

Did you mean to call this expression?

And I can easily override the DefaultTheme with:

declare module "@emotion/core" {
  interface DefaultTheme {
    ...
  }
}

@WestonThayer
Copy link
Author

I think you make good points in #1507 (comment) though.

Maybe the answer is that I should be using emotion instead of @emotion/core. Losing the NODE_ENV === "development friendly class names that @emotion/core's css provides would be a bit of a bummer though.

Or maybe this should be solved via an ESLint rule rather than via TypeScript.

@Andarist
Copy link
Member

With vanilla emotion you won't have eassy theme access though. I think we are going to go with DefaultTheme approach in the end, but we'd also like to promote creating your own themes with #1577 to avoid problems described in #1507 (comment) and in #973 . This all is still in the works though so stay tuned.

@JakeGinnivan
Copy link
Contributor

A manual backwards compat step would be to add instructions to do this:

declare module "@emotion/core" {
  interface DefaultTheme {
    [key: string]: any
  }
}

@WestonThayer
Copy link
Author

FWIW this is fixed in Emotion 11.

@hugotox
Copy link

hugotox commented Mar 15, 2022

FWIW on a monorepo setup with several parties using emotion (in my case, chakra, storybook and my own stuff) I had to add a resolution to @emotion/serialize in my top level package.json as that was causing multiple versions to confuse typescript

"resolutions": {
    "@emotion/react": "11.7.1",
    "@emotion/serialize": "1.0.2"
  }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants