Closed SpencerDuball closed 3 years ago
Ok I have found a solution for this issue, it looks like the type conflict is because the original props to svg
from TypeScript are also still present on <x.svg>
instead of only the props from xstyled.
The workaround is to omit the original props from svg
that are supplied from TypeScript, example below:
import { SVGProps } from "react";
import { x, SvgProps } from "@xstyled/styled-components";
type SvgPropsKeys = keyof SVGProps<SVGElement>;
interface JFEIconProps extends Omit<SvgProps, SvgPropsKeys> {}
export const JFEIcon = (props: JFEIconProps) => (
<x.svg fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<circle cx="194.667" cy="134.333" r="5.867" fill="#E1D29D" />
</x.svg>
);
Note that this solves the issue for all TypeScript utilities applied to the x.svg
element, for example extending SystemProps
like the example below would pass all of the props that x.svg
could use.
import { SVGProps } from "react";
import { x, SystemProps } from "@xstyled/styled-components";
type SvgPropKeys = keyof SVGProps<SVGElement>;
interface JFEIconProps extends Omit<SystemProps, SvgPropKeys> {}
export const JFEIcon = (props: JFEIconProps) => (
<x.svg fill="none" xmlns="http://www.w3.org/2000/svg" {...props}>
<circle cx="194.667" cy="134.333" r="5.867" fill="#E1D29D" />
</x.svg>
);
I think this is probably a bug now that I understand the issue better, the solution provided in this comment will work as a workaround but I will investigate for a more permanent fix so that this is not an issue out-of-box.
It is normal that <x.svg />
accepts SVG props and xstyled props.
Just want to leave this comment here for anyone that might run into this issue, this is a drop in solution that you can use to resolve these type conflicts.
I think that <x.svg>
should accept SVG props, but I think it might be better to remove the intersecting types and prefer the type definitions from <x.svg>
only when using that component instead of also the type definitions from React.SVGProps<SVGSVGElement>
.
When styling on HTML elements such as <x.p>
we are adding props such as backgroundColor
that are then applied via the class
property, but with <x.svg>
we are not adding props, but replacing props such as fill
. This is an issue because fill
has both the type definitions of React.SVGProps<SVGSVGElement>
and SystemProps
, and in this case there is a type conflict when trying to set attributes such as fill
to a string (see original issue for details on this error).
An example of removing the intersecting types is provided below in the workaround and the component is working as expected.
Create a new file called XSvg.tsx
(or whatever name is preferred), and use this instead of x.svg
:
// XSvg.tsx
import { x, SystemProps } from "@xstyled/emotion";
import React from "react";
// fix for <x.svg> type conflicts
type XSvgKeys = keyof Omit<SystemProps, "children">;
type UniqueIntrinsicSvgProps = Omit<React.SVGProps<SVGSVGElement>, XSvgKeys>;
export interface XSvgProps extends UniqueIntrinsicSvgProps, SystemProps {}
export const XSvg: (props: XSvgProps) => JSX.Element = x.svg as any;
And an example use case:
// Abacus.tsx
import React from "react";
import { SystemProps } from "@xstyled/emotion";
import { XSvg } from "utility";
export interface AbacusPropsI extends SystemProps {}
export const Abacus = (props: AbacusPropsI) => (
<XSvg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="black"
{...props}
>
<path d="M21,2a1,1,0,0,0-1,1V6H16V5a1,1,0,0,0-2,0V6H12V5a1,1,0,0,0-2,0V6H8V5A1,1,0,0,0,6,5V6H4V3A1,1,0,0,0,2,3V19a3,3,0,0,0,3,3H19a3,3,0,0,0,3-3V3A1,1,0,0,0,21,2ZM20,19a1,1,0,0,1-1,1H5a1,1,0,0,1-1-1V16H6v1a1,1,0,0,0,2,0V16h2v1a1,1,0,0,0,2,0V16h4v1a1,1,0,0,0,2,0V16h2Zm0-5H18V13a1,1,0,0,0-2,0v1H12V13a1,1,0,0,0-2,0v1H8V13a1,1,0,0,0-2,0v1H4V8H6V9A1,1,0,0,0,8,9V8h2V9a1,1,0,0,0,2,0V8h2V9a1,1,0,0,0,2,0V8h4Z" />
</XSvg>
);
š¬ Questions and Help
I am trying to pass props to the
<x.svg>
element below, but am getting errors that I am not having when passing props to other elements such as<x.div>
for instance. I looked over the XStyled documentation & source code, styled-components documentation & source code, and TypeScript guide but can't seem to figure this out.I would like to pass ALL props that
<x.svg>
can accept ideally, but run into errors extending most of the props. I have tried many different combinations of interfaces and types to pass but keep running into this error.This will give me this error:
Even with other props such as
LayoutProps
for example, I will still have a mismatch on types. Any help would be greatly appreciated to figure this out. I would be happy to submit a pull request to add the solution to the TypeScript documentation on the website too in order to make this easier for future users.