Emotion: Augmenting the DOMAttributes interface with 'css' causes conflicts

Created on 5 Mar 2019  路  9Comments  路  Source: emotion-js/emotion

  • emotion version: 10.0.7
  • react version: 16.8.3

Relevant code:

// NOTE: the code doesn't actually use emotion at all,
// it's an indirect devDependency; but if emotion's types are loaded at all,
// it causes conflicts.
import {} from '@emotion/core'
import styled from 'styled-components'
/// <reference types="styled-components/cssprop"/>

// If I use React.ComponentPropsWithoutRef<'a'> instead there is no conflict,
// but the component I am trying to use does use AnchorHTMLAttributes
interface Props extends React.AnchorHTMLAttributes<HTMLAnchorElement> {
  // the foo doesn't matter, it's just to demonstrate object rest
  foo: boolean
}

export default function WrappedLink({ foo, ...props }: Props) {
  return <A {...props} />
}

// the style doesn't matter
const A = styled.a``

What you did:

In a project that already used styled-components, @emotion/core started being loaded as an indirect devDependency (@storybook/theming, to be more specific).

What happened:

The combination of an augmented React.DOMAttributes with a double-augmented JSX.Attributes is breaking pass-through of the props because the React.DOMAttributes makes the component think it can receive css as a prop.

Type '{ download?: any; href?: string | undefined; hrefLang?: string | undefined; media?: string | undefined; rel?: string | undefined; target?: string | undefined; type?: string | undefined; ... 251 more ...; css?: InterpolationWithTheme<...>; }' is not assignable to type '{ className?: string | undefined; download?: any; href?: string | undefined; hrefLang?: string | undefined; media?: string | undefined; rel?: string | undefined; target?: string | undefined; ... 253 more ...; key?: string | ... 1 more ... | undefined; }'.
  Types of property 'css' are incompatible.
    Type 'InterpolationWithTheme<any>' is not assignable to type 'string | (string & ComponentSelector) | (string & { name: string; styles: string; anim: number; toString: () => string; }) | (string & SerializedStyles) | (string & ArrayInterpolation<undefined>) | ... 12 more ... | undefined'.
      Type 'null' is not assignable to type 'string | (string & ComponentSelector) | (string & { name: string; styles: string; anim: number; toString: () => string; }) | (string & SerializedStyles) | (string & ArrayInterpolation<undefined>) | ... 12 more ... | undefined'.

Reproduction:

CodeSandbox can't typecheck, even in typescript sandboxes :(

Problem description:

@emotion/core unconditionally augments both React.DOMAttributes and JSX.Attribute, but ideally such augmentation should be optional to avoid this conflict.

Suggested solution:

@types/styled-components made it optional by splitting just the augmentation itself into a separate file, and you can request it by adding "styled-components/cssprop" to your tsconfig.json's compilerOptions.types, using a triple-slash reference (only needed once, on any file that's in the project) as in the above sample, or using an empty import (also only needed once).

The augmentation of React.DOMAttributes is technically unnecessary, augmenting React.Attributes is sufficient for all JSX use cases (JSX.Attributes inherits from React.Attributes). The only thing it makes possible is _receiving_ css as a prop, which you can't, even with / especially with the jsx pragma.

The added advantage of making the augmentation optional is that it makes it possible for the user to augment it with a more specific type -- perhaps InterpolationWithTheme<MyTheme>, for example.


EDIT: This also, of course, affects actual uses of css with the styled-components css function, as it becomes impossible to fulfill the type. The only workarounds I can do until this is fixed is to locally augment the css prop in both interfaces with any (!).

TypeScript

Most helpful comment

+1 Also ran into this via storybook

All 9 comments

+1 Also ran into this via storybook

The emotion css prop type coming with Storybook brought me here too. I've managed to fix this for myself by adding @emotion/core types to a .yarnclean file.

echo @emotion/core/types >> .yarnclean
yarn

Thanks @jvgreenaway! That fix works just fine.

For those that are, like me, not using yarn. He's just deleting the file directly after install. So a pm postinstall hook could do the same:

"scripts": {
  "postinstall": "rimraf node_modules/@emotion/core/types"
}

A fix for this has been just merged into v11 line: https://github.com/emotion-js/emotion/pull/1941

If you have errors with types "type" and "as" you should redefine this types before intert these in styled components. Perhaps, if you try to rewrite css-props, it will help. My example:

/* Button component */
const Button: React.FC<ButtonProps> = ({
  isLoading,
  children,
  // should redefine this types because React.HTMLProps<HTMLButtonElement> has incompatible similar types
  type = 'button',
  as = undefined,
  ...props
}: ButtonProps, ...others) => {
  return (
    <StyledButton {...props} {...others}>
      {isLoading ? 'Loading...' : children}
    </StyledButton>
  );
};

export default Button;

Hello all,

I want to point out that this conflict still exist when trying to use a component styled with https://github.com/modulz/stitches in the context of storybook :

image

The only solution right now is to add @emotion/core/types to .yarnclean when using storybook.

This has been fixed in v11 - @emotion/core is a package only available in v10.

Hello all,

I want to point out that this conflict still exist when trying to use a component styled with https://github.com/modulz/stitches in the context of storybook :

image

The only solution right now is to add @emotion/core/types to .yarnclean when using storybook.

You're right. Storybook v6 references @emotion/core v10 as dependency that has global css type yet, and it occurs type error if we pass css style of object. it conflicts with @emotion/react v11. If you use storybook v6, the only solution is to remove @emotion/core/types.

The emotion css prop type coming with Storybook brought me here too. I've managed to fix this for myself by adding @emotion/core types to a .yarnclean file.

echo @emotion/core/types >> .yarnclean
yarn

I also had to add @storybook/theming/node_modules/@emotion/core/types to .yarnclean.

Was this page helpful?
0 / 5 - 0 ratings