MathiasGilson/Tailwind-Styled-Component

Polymorphic Component: "Type instantiation is excessively deep and possibly infinite"

aplr opened this issue ยท 13 comments

aplr commented

When using the $as prop of my StyledButton, typescript complains with the following error on StyledButton:

Type instantiation is excessively deep and possibly infinite. ts(2589)

Here's a small example:

import { ComponentProps, ElementType, PropsWithChildren } from "react"
import tw from "tailwind-styled-components"

type ButtonOwnProps<E extends ElementType> = PropsWithChildren<{
  as?: E
  pill?: boolean
}>

type ButtonProps<E extends ElementType> = ButtonOwnProps<E> & ComponentProps<E>

const StyledButton = tw.button<{ $size: ButtonSize; $style: ButtonStyle; $pill: boolean }>`
px-3
py-2
inline-flex
items-center
font-medium
text-base
bg-blue-600
text-white

${({ $pill }) => $pill ? "rounded-full" : "rounded-md"}
`

export const Button = <E extends ElementType = "button">({
  as,
  pill = false,
  children,
  ...props
}: ButtonProps<E>) => (
  <StyledButton $as={as} $pill={pill} {...props}> // Type instantiation is excessively deep and possibly infinite. ts(2589)
    {children}
  </StyledButton>
)

Just by using a simple tw.div and putting a tw.imginside the div I'm getting this error.
I'm using Styled Components with Theme Provider as well.
This error is annoying.

I had the same problem when I need to pass parameters, for now I solved it by putting:

twd.button<any>

And when I need to have variations, I use inheritance:

export const BoxDefault = twd.button<any>``;
export const BoxInheritance = twd(BoxDefault)``;

If anyone else has another suggestion to solve this, I didn't find a very elegant solution but it was the way I found to get around it.

@Dudeonyx Could you have a look if you have the time ? ๐Ÿ™

First thanks for your work ! Hope to see a fix in the next release ;) For now I downgraded to 2.1.7 to keep it "work"

Are there any updates on this? Downgrading to 2.1.7 is no good because it doesn't seem to have a good typescript support as the default tw export is of type any

Also excited to see a fix for this (linting errors for this make me crazy)... FWIW, downgrading did not solve the issue for me.

For now, I created a Wrapper to use @bpinheiroms ' solution (just to get rid of the linting errors)

Here it is:

import React, { ComponentProps } from "react";

interface ExoticComponentWithDisplayName<P = unknown>
    extends React.ExoticComponent<P> {
    defaultProps?: Partial<P>;
    displayName?: string;
}

export type AnyComponent<P = any> =
    | ExoticComponentWithDisplayName<P>
    | React.ComponentType<P>;

export type KnownTarget = keyof JSX.IntrinsicElements | AnyComponent;

const tw = (Tag: KnownTarget) => (twClasses: TemplateStringsArray) => {
    const NewComponent = ({
        children,
        ...props
    }: ComponentProps<KnownTarget>) => {
        let cssClasses = twClasses.toString();

        if (props.className !== undefined) {
            cssClasses += " " + props.className;
        }

        if (!twClasses) {
            return <Tag {...props}>{children}</Tag>;
        } else {
            return (
                <Tag {...props} className={cssClasses}>
                    {children}
                </Tag>
            );
        }
    };
    return NewComponent;
};

tw.a = tw("a");
tw.abbr = tw("abbr");
tw.address = tw("address");
tw.area = tw("area");
tw.article = tw("article");
tw.aside = tw("aside");
tw.audio = tw("audio");
tw.b = tw("b");
tw.base = tw("base");
tw.bdi = tw("bdi");
tw.bdo = tw("bdo");
tw.big = tw("big");
tw.blockquote = tw("blockquote");
tw.body = tw("body");
tw.br = tw("br");
tw.button = tw("button");
tw.canvas = tw("canvas");
tw.caption = tw("caption");
tw.cite = tw("cite");
tw.code = tw("code");
tw.col = tw("col");
tw.colgroup = tw("colgroup");
tw.data = tw("data");
tw.datalist = tw("datalist");
tw.dd = tw("dd");
tw.del = tw("del");
tw.details = tw("details");
tw.dfn = tw("dfn");
tw.dialog = tw("dialog");
tw.div = tw("div");
tw.dl = tw("dl");
tw.dt = tw("dt");
tw.em = tw("em");
tw.embed = tw("embed");
tw.fieldset = tw("fieldset");
tw.figcaption = tw("figcaption");
tw.figure = tw("figure");
tw.footer = tw("footer");
tw.form = tw("form");
tw.h1 = tw("h1");
tw.h2 = tw("h2");
tw.h3 = tw("h3");
tw.h4 = tw("h4");
tw.h5 = tw("h5");
tw.h6 = tw("h6");
tw.head = tw("head");
tw.header = tw("header");
tw.hgroup = tw("hgroup");
tw.hr = tw("hr");
tw.html = tw("html");
tw.i = tw("i");
tw.iframe = tw("iframe");
tw.img = tw("img");
tw.input = tw("input");
tw.ins = tw("ins");
tw.kbd = tw("kbd");
tw.keygen = tw("keygen");
tw.label = tw("label");
tw.legend = tw("legend");
tw.li = tw("li");
tw.link = tw("link");
tw.main = tw("main");
tw.map = tw("map");
tw.mark = tw("mark");
tw.menu = tw("menu");
tw.menuitem = tw("menuitem");
tw.meta = tw("meta");
tw.meter = tw("meter");
tw.nav = tw("nav");
tw.noindex = tw("noindex");
tw.noscript = tw("noscript");
tw.object = tw("object");
tw.ol = tw("ol");
tw.optgroup = tw("optgroup");
tw.option = tw("option");
tw.output = tw("output");
tw.p = tw("p");
tw.param = tw("param");
tw.picture = tw("picture");
tw.pre = tw("pre");
tw.progress = tw("progress");
tw.q = tw("q");
tw.rp = tw("rp");
tw.rt = tw("rt");
tw.ruby = tw("ruby");
tw.s = tw("s");
tw.samp = tw("samp");
tw.slot = tw("slot");
tw.script = tw("script");
tw.section = tw("section");
tw.select = tw("select");
tw.small = tw("small");
tw.source = tw("source");
tw.span = tw("span");
tw.strong = tw("strong");
tw.style = tw("style");
tw.sub = tw("sub");
tw.summary = tw("summary");
tw.sup = tw("sup");
tw.table = tw("table");
tw.template = tw("template");
tw.tbody = tw("tbody");
tw.td = tw("td");
tw.textarea = tw("textarea");
tw.tfoot = tw("tfoot");
tw.th = tw("th");
tw.thead = tw("thead");
tw.time = tw("time");
tw.title = tw("title");
tw.tr = tw("tr");
tw.track = tw("track");
tw.u = tw("u");
tw.ul = tw("ul");
tw.var = tw("var");
tw.video = tw("video");
tw.wbr = tw("wbr");
tw.webview = tw("webview");
tw.svg = tw("svg");
tw.animate = tw("animate");
tw.animateMotion = tw("animateMotion");
tw.animateTransform = tw("animateTransform");
tw.circle = tw("circle");
tw.clipPath = tw("clipPath");
tw.defs = tw("defs");
tw.desc = tw("desc");
tw.ellipse = tw("ellipse");
tw.feBlend = tw("feBlend");
tw.feColorMatrix = tw("feColorMatrix");
tw.feComponentTransfer = tw("feComponentTransfer");
tw.feComposite = tw("feComposite");
tw.feConvolveMatrix = tw("feConvolveMatrix");
tw.feDiffuseLighting = tw("feDiffuseLighting");
tw.feDisplacementMap = tw("feDisplacementMap");
tw.feDistantLight = tw("feDistantLight");
tw.feDropShadow = tw("feDropShadow");
tw.feFlood = tw("feFlood");
tw.feFuncA = tw("feFuncA");
tw.feFuncB = tw("feFuncB");
tw.feFuncG = tw("feFuncG");
tw.feFuncR = tw("feFuncR");
tw.feGaussianBlur = tw("feGaussianBlur");
tw.feImage = tw("feImage");
tw.feMerge = tw("feMerge");
tw.feMergeNode = tw("feMergeNode");
tw.feMorphology = tw("feMorphology");
tw.feOffset = tw("feOffset");
tw.fePointLight = tw("fePointLight");
tw.feSpecularLighting = tw("feSpecularLighting");
tw.feSpotLight = tw("feSpotLight");
tw.feTile = tw("feTile");
tw.feTurbulence = tw("feTurbulence");
tw.filter = tw("filter");
tw.foreignObject = tw("foreignObject");
tw.g = tw("g");
tw.image = tw("image");
tw.line = tw("line");
tw.linearGradient = tw("linearGradient");
tw.marker = tw("marker");
tw.mask = tw("mask");
tw.metadata = tw("metadata");
tw.mpath = tw("mpath");
tw.path = tw("path");
tw.pattern = tw("pattern");
tw.polygon = tw("polygon");
tw.polyline = tw("polyline");
tw.radialGradient = tw("radialGradient");
tw.rect = tw("rect");
tw.stop = tw("stop");
tw.switch = tw("switch");
tw.symbol = tw("symbol");
tw.text = tw("text");
tw.textPath = tw("textPath");
tw.tspan = tw("tspan");
tw.use = tw("use");
tw.view = tw("view");

export default tw;

and in my components instead of importing tw directly from TailWindStyledComponents I'm importing from my wrapper

@GabrielOGabs
Unfortunately for me, this doesn't support injected properties, example:

type LabelProps = {
  type: FieldName,
  selected: FieldName | undefined
}

export const Label = tw.p<LabelProps>`
pl-1
text-justify
    ${(x) => x.type === x.selected ? "bg-indigo-300 rounded-lg" : ""}
`

What fixed it for me was switching my VS code TS version to 4.9. Before, I was using 4.8

What fixed it for me was switching my VS code TS version to 4.9. Before, I was using 4.8

That worked for me; link here how how to change TS version in VS Code
https://stackoverflow.com/a/39676463

What's the status on this? I've just run into this error and it's a bit of a dealbreaker as I can't put a button styled with tw inside a div styled with tw.

If someone familiar with the project could help me out I'd like to lend a hand fixing this, but I'm relatively new to oss.

I also get the same error but without using it as a polymorphic component.

const TwSelect = tw.select``;

This works fine

export const Select = () => (
  <TwSelect style={{ border: "1px solid red" }}>
    {/* without children */}
  </TwSelect>
);

This gives the ts(2589) error

export const Select = () => (
  <TwSelect style={{ border: "1px solid red" }}>
    <div />
  </TwSelect>
);

Can anyone reproduce this in version 2.2.0?

image

Any solution?