Current behavior:
The @emotion/core/types/index.d.ts file from the package includes the following declarations:
declare module 'react' {
interface DOMAttributes<T> {
css?: InterpolationWithTheme<any>
}
}
declare global {
namespace JSX {
/**
* Do we need to modify `LibraryManagedAttributes` too,
* to make `className` props optional when `css` props is specified?
*/
interface IntrinsicAttributes {
css?: InterpolationWithTheme<any>
}
}
}
This causes the global scope to become polluted with @emotion types, even though the user might not be asking for it - eg. it came as a surprise to me, because @emotion is a dependency of storybook, and I didn't know about it until I tried using the css prop for styled-components and there was no error.
Further, after including styled-components type declaration for the css prop, some strange errors emerged because of the way TypeScript handles declaration merging:
Types of property 'css' are incompatible.
Type 'string | CSSObject | FlattenInterpolation<ThemeProps<any>> | undefined' is not
assignable to type 'InterpolationWithTheme<any>'.
Type 'FlattenInterpolation<ThemeProps<any>>' is not assignable to type 'InterpolationWithTheme<any>'.
Type 'FlattenInterpolation<ThemeProps<any>>' is not assignable to type 'ObjectInterpolation<undefined>'.
Expected behavior:
I'd expect a mechanism similar to styled-components/cssprop: the user has to manually create a file which imports global declarations instead of pullution by default.
Environment information:
@emotion/[email protected]
As a workaround I think you can use a whitelist of global types by providing the types config in TSConfig, which I think would allow you to not automatically include random globals included by other libraries
Unfortunately this doesn't work:
@storybook/addon-knobs@storybook/addon-knobs/dist/components/types/index.d.ts/// <reference types="@emotion/core" />... so TypeScript imports the file anyway.
Now that I think of it, even if you switch to an opt-in behavior, Storybook will still need to avoid polluting the global scope by explicitly providing a type for the css prop as opposed to hypothetically importing @emotion/core/cssprop. But that's the next step.
So for now I guess I'll stick to rm @emotion/.../index.d.ts in postinstall in package.json 馃槀
Is there a way to stop TS from importing a file automatically? Actually, when I've re-read your answer @fatfisz I've noticed you have added some nice extra info I was missing before. That @storybook includes the reference to @emotion/core.
I'm going to think about how this can be solved, but if you have any ideas of your own I would highly appreciate any help with this.
This is also a duplicate of https://github.com/emotion-js/emotion/issues/1257
One more thing, would you be able to prepare a minimal repro case for this? It would allow me to jump into this issue much sooner.
Sorry, I didn't manage to find the previous issue. My suggested solution is the same as styled-components:
CSSProp or similar that will be equal to InterpolationWithTheme<any>styled-components/cssprop that injects the css?: CSSProp property into the global scope. In the case of styled-components it's not in the library itself, but rather in @types/styled-components, but it shouldn't matterThe benefits I see here are:
css to only a few components (eg. because of a migration from another tool or in the case of Storybook to prevent the global leak), one can always refer to CSSProp directlyHere's my smallest reproduction repo: https://github.com/fatfisz/emotion-global-type-injection-repro.
Provide a separate type file like styled-components/cssprop that injects the css?: CSSProp property into the global scope. In the case of styled-components it's not in the library itself, but rather in @types/styled-components, but it shouldn't matter
The problem I see with that is that you would still probably bump into this issue because StoryBooks would still refer to this file and would drag this global pollution into your build, wouldn't it?
Yes, as I mentioned previously:
Now that I think of it, even if you switch to an opt-in behavior, Storybook will still need to avoid polluting the global scope by explicitly providing a type for the css prop as opposed to hypothetically importing @emotion/core/cssprop. But that's the next step.
But without Emotion fixing the problem first, Storybook can't do anything. I can only promise that I'll take it up with them afterwards 馃檪
But even if we are going to fix it in a way you have proposed I'm still unsure how they could utilize css prop without polluting the global types. What would be the recommendation for them if we make css prop types opt-in?
Each of the exported components that is actually using Emotion's css should explicitly have it in their interface; I don't know much about the structure of that project, but on a quick glance KnobControlProps seems like a good place, because all knob components extend it:
import { CSSProp } from '@emotion/...'; // Just importing the type shouldn't pollute the global scope
export interface KnobControlProps<T> {
css?: CSSProp; // Just define the css prop explicitly here
knob: KnobControlConfig<T>;
onChange: (value: T) => T;
}
Any news on this?
It's quite frustrating since there's no clean way to solve this problem while using styled-components.
I've just run into this building a component library on top of theme-ui. I have a <Box> component with a css prop that passes styles to theme-ui's sx prop. For this to work I have to comment out a line in the @emotion/core/types/index.d.ts file.
declare global {
namespace JSX {
/**
* Do we need to modify `LibraryManagedAttributes` too,
* to make `className` props optional when `css` props is specified?
*/
interface IntrinsicAttributes {
// css?: InterpolationWithTheme<any>
}
}
}
I have this problem with styled-components too, where I have to explicitly annotate props in a template string, even though styled-components itself can properly infer the type. If I manually remove the *.d.ts files in @emotion, the problem goes away. The strange thing is, though, that VSCode does properly infer the props type when on mouseover of the parameter. For now, the only solution I have is a postinstall rm -rf.
I believe I have found an appropriate fix for this on our end - if anyone wants to take a look then here it is: https://github.com/emotion-js/emotion/pull/1941 . Keep in mind that it targets the upcoming v11 that we hope to ship soon.
A fix for this has been just merged into v11 line: https://github.com/emotion-js/emotion/pull/1941