styled-components icon indicating copy to clipboard operation
styled-components copied to clipboard

styled-components v6 beta feedback

Open quantizor opened this issue 3 years ago • 11 comments

Starting a new thread for issues related to beta npm tag.

quantizor avatar Sep 10 '22 14:09 quantizor

It looks like styled components don't emit an error on missing props:

import styled from 'styled-components'

type Props = {requiredProp: boolean}

const A = (_props: Props) => <div />
const a = <A />  // error for missing requiredProp ✅

const B = styled.div<Props>``
const b = <B />  // no error for missing requiredProp ❌

Sandbox at https://codesandbox.io/s/blue-mountain-g3vsfr?file=/src/App.tsx


This appears to be caused by

export interface BaseExtensibleObject {
  [key: string]: any;
}

Because of this declaration, styled components will never generate errors for missing props.

The motivation behind this declaration isn't clear to me. When I comment it out, everything seems to work in my limited testing:

export interface BaseExtensibleObject {
  // [key: string]: any;
}

but I'm probably missing something.

agriffis avatar Sep 10 '22 14:09 agriffis

Here is the problem that @TmLev reported. Specifically, styled(Custom).attrs() seems to break typing of properties:

// gridColumn is number in the interpolation ✅
const StyledDiv = styled.div.attrs({device: 'mobile'})<{gridColumn: number}>`
  grid-column: ${({gridColumn}) => gridColumn};
`

const Custom = (props: ComponentProps<'div'>) => <div {...props} />

// gridColumn is number in the interpolation ✅
const StyledCustom = styled(Custom)<{gridColumn: number}>`
  grid-column: ${({gridColumn}) => gridColumn};
`

// gridColumn is any in the interpolation ❌
const StyledCustomWithAttrs = styled(Custom).attrs({device: 'mobile'})<{
  gridColumn: number
}>`
  grid-column: ${({gridColumn}) => gridColumn};
`

Sandbox link: https://codesandbox.io/s/serverless-dream-jmoplr?file=/src/App.tsx

agriffis avatar Sep 10 '22 16:09 agriffis

Here is the other problem I reported. This one is a bit annoying with all the nesting, but it seems to be necessary to trigger.

const moreStyles = css``

const Outer = styled.div``

const Inner = styled.div`
  ${css`
    ${css`
      ${Outer} {
        color: green;
      }
    `}
    ${moreStyles}
  `}
`
Argument of type 'string | number | TemplateStringsArray | Keyframes | IStyledComponent<"web", any, any> | StyledObject<ClassAttributes<HTMLDivElement> & HTMLAttributes<...>> | StyleFunction<...> | (Interpolation<...>[] & { ...; }) | null | undefined' is not assignable to parameter of type 'Interpolation<unknown>'.
  Type 'StyleFunction<ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement>>' is not assignable to type 'Interpolation<unknown>'.
    Type 'StyleFunction<ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement>>' is not assignable to type 'StyleFunction<unknown>'.
      Type 'unknown' is not assignable to type 'ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement>'.
        Type 'unknown' is not assignable to type 'ClassAttributes<HTMLDivElement>'.ts(2345)

Sandbox link: https://codesandbox.io/s/admiring-violet-tjodr6?file=/src/App.tsx

agriffis avatar Sep 10 '22 16:09 agriffis

These types are pretty complicated to say the least, will keep working on them

quantizor avatar Sep 10 '22 16:09 quantizor

@probablyup I've been fiddling with some stuff, specifically:

  • kill BaseExtensibleObject (and use Dict<any> explicitly in places that need that kind of thing, where type Dict<T> = {[k: string]: T})
  • rename ExtensibleObject to ExecutionProps since it's essentially a partial ExecutionContext
  • change lots of <Props = unknown> to <Props extends {}>

These changes resolve at least some of the problems above.

I can make a PR but I already have a few in the pipe and I'm not sure how keen you are on receiving them versus working on it yourself. Lemme know what you'd like me to do. I could probably find time today to pair if you'd want to look at things together.

agriffis avatar Sep 11 '22 15:09 agriffis

PRs would be great, thank you 😄

quantizor avatar Sep 11 '22 15:09 quantizor

Hi,

Is there a plan to implement a new way (or fix the old way) of namespacing the generated CSS? The method described here no longer works because babel-plugin-styled-components-css-namespace hasn't worked since 5.2.0

I've been stuck on 5.1.1 and React 17 as a result and not been able to find a work around.

marmite22 avatar Sep 12 '22 10:09 marmite22

@marmite22 If all you need is namespacing for isolation, then you can configure the babel plugin for that and the same functionality is available in the swc plugin. But if you need namespacing for the sake of increased specificity on a global level, then I'll go out on a limb and say there's no plan. If stuff is broken over a few releases then I interpret that as something @probablyup doesn't rely on personally, and so fixing it depends on someone else stepping up with a PR. Sounds like it's time for you to jump in. :smile:

agriffis avatar Sep 12 '22 18:09 agriffis

I added another PR that seems to fix the problem @TmLev reported, see https://github.com/styled-components/styled-components/pull/3809

It builds on my previous PRs so just look at the last commit

(That means all the problems above are theoretically solved.)

agriffis avatar Sep 13 '22 00:09 agriffis

I'm running into typing issues when using a styled component definition as an interpolation within css. Note the issue only occurs if both styled component definitions include custom prop types.

Argument of type '() => string | number | TemplateStringsArray | Keyframes | IStyledComponent<"web", any, any> | StyledObject<ClassAttributes<HTMLDivElement> & HTMLAttributes<...> & { ...; }> | StyleFunction<...> | (Interpolation<...>[] & { ...; }) | null | undefined' is not assignable to parameter of type 'Interpolation<ExecutionContext & ClassAttributes<HTMLDivElement> & HTMLAttributes<HTMLDivElement> & { ...; }>'.
  Type '() => string | number | TemplateStringsArray | Keyframes | IStyledComponent<"web", any, any> | StyledObject<ClassAttributes<HTMLDivElement> & HTMLAttributes<...> & { ...; }> | StyleFunction<...> | (Interpolation<...>[] & { ...; }) | null | undefined' is missing the following properties from type 'IStyledComponent<"web", any, any>': $$typeof, componentStyle, foldedComponentIds, inlineStyle, and 4 more.ts(2345)

Here's a minimal reproduction:

import styled, { css } from 'styled-components';

const StyledBox = styled.div<{ bar: boolean }>``;

const Example = styled.div<{ foo: boolean }>`
  /* no error */
  ${StyledBox} {
      color: blue;
  }

  /* causes error */
  ${() => css`
      ${StyledBox} {
          color: blue;
      }
  `}
`;

Also seems that including this type of interpolation will incorrectly affect the inferred type of the styled component. image

const StyledButton = styled.button``;

const Example2 = styled.div`
  ${StyledButton} {
    color: blue;
  }
`;

joshjg avatar Sep 14 '22 20:09 joshjg

I'm also getting this cryptic error when running tsc in my project. Seems some of TypeScript's internal state is overflowing due to inefficient types:

tsc:
/<repo>/node_modules/typescript/lib/tsc.js:96888
                throw e;
                ^

RangeError: Value undefined out of range for undefined options property undefined
    at Map.set (<anonymous>)
    at recursiveTypeRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54455:30)
    at isRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54019:25)
    at typeRelatedToSomeType (/<repo>/node_modules/typescript/lib/tsc.js:54239:35)
    at unionOrIntersectionRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54194:28)
    at structuredTypeRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54509:34)
    at recursiveTypeRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54431:30)
    at isRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54019:25)
    at eachTypeRelatedToType (/<repo>/node_modules/typescript/lib/tsc.js:54299:35)
    at unionOrIntersectionRelatedTo (/<repo>/node_modules/typescript/lib/tsc.js:54191:25)

I suspect the definition of PolymorphicComponentProps contributes to this issue but I'm not sure, this is hard to debug. If I replace this line with ActualComponentProps = {} I don't get this error. (But obviously the type is inaccurate)

There are several instances of types like this which map over JSX.IntrinsicElements, contributing to slowness. @types/styled-components (v5) does not hit the overflow issue, but it is possibly the slowest part of TS compilation in my project. I'm hopeful that this can be addressed somehow in the new implementation.

EDIT:

Apparently this has already come up as a TypeScript issue and will be fixed in 4.9. I tried out a pre-build of 4.9 and indeed the error was gone. However, the total compilation time is still significantly longer than with @types/styled-components. https://github.com/microsoft/TypeScript/issues/50290

joshjg avatar Sep 15 '22 20:09 joshjg

@container rules ONLY work if no cascade is applied.

https://codesandbox.io/s/trusting-mahavira-pf8pnx?file=/src/App.tsx

Screenshot 2022-09-26 at 10 44 00

DYCrypto avatar Sep 26 '22 09:09 DYCrypto

@DYCrypto Is that related to changes in v6? Seems to be the same behavior for me on v5.x. Could you please report it as a separate issue?

agriffis avatar Sep 26 '22 16:09 agriffis

@container queries don't work at all in 5, and codesandbox doesn't reflect realtime updates unless you change, save and then refresh the browser, which gives false positives. I updated the package in above and had to save and then refresh to see real world example.

I found that SC will only support @container queries from 6, which is sort of does but not fully as above..

see this issues: https://github.com/styled-components/styled-components/issues/3763 re the transpiler prior to 6

DYCrypto avatar Sep 26 '22 20:09 DYCrypto

@DYCrypto Thanks for the clarification. Looks like this will depend on a change in stylis, see https://github.com/thysultan/stylis/issues/303

agriffis avatar Sep 27 '22 13:09 agriffis

@joshjg Thanks for the specific problem reports. I rebased https://github.com/styled-components/styled-components/pull/3809 and I expect @probablyup will merge it pretty soon. It won't fix your reports but I think provides a stepping stone. When that's merged, it would be great if you had a chance to put together a PR.

One thing that's missing in all of this is integrated tests for the types. Would love to get some help on that too. I saw https://github.com/TypeStrong/ts-expect which looks good on the surface, but if anybody has experience writing tests for types, it would be great to get some input and help on this.

agriffis avatar Sep 27 '22 13:09 agriffis

Actually I think it was this one that looked attractive: https://github.com/mmkal/expect-type

agriffis avatar Sep 27 '22 13:09 agriffis

Just published v6.0.0-beta.3 with a ton of type fixes, thanks @agriffis and @alexandernanberg for contributing! https://github.com/styled-components/styled-components/releases/tag/v6.0.0-beta.3

quantizor avatar Oct 04 '22 04:10 quantizor

Hi,

Quick question about v6 :

breaking removed runtime prop validation functionality; use transient props for styling-only props or shouldForwardProp for more advanced scenarios

Does this mean that the default validator inside shouldForwardProp is dropped ?

LoiKos avatar Oct 04 '22 07:10 LoiKos

@LoiKos

Does this mean that the default validator inside shouldForwardProp is dropped ?

Yes, see 6baaea48

agriffis avatar Oct 04 '22 13:10 agriffis

Here are a couple confusing things I'm seeing in beta 3:

  1. TS error trying to destructure theme from props, see X and Y in sandbox
  2. Styled component props seems to lack as, hover over ZProps in same sandbox

Sandbox link: https://codesandbox.io/s/styled-components-v6-forked-3ehn9o

agriffis avatar Oct 05 '22 14:10 agriffis

TS error trying to destructure theme from props, see X and Y in sandbox

It's actually the use of css ttl that it's complaining about, if you reduce it to a simple interpolation it works:

const X = styled.h1`
  color: ${({ theme }) => theme.colors.red};
`

I'll take a look at the Interpolation type and see if something needs to be done...

Styled component props seems to lack as, hover over ZProps in same sandbox

Interesting, if you compose Z as jsx it takes and resolves the as just fine. Will look into it.

quantizor avatar Oct 05 '22 18:10 quantizor

@probablyup I think that #3825 fixes the as problem.

agriffis avatar Oct 06 '22 17:10 agriffis

@probablyup and #3826 just might fix the interpolations problem

agriffis avatar Oct 07 '22 01:10 agriffis

@agriffis @probablyup Opened #3827 to fix the issues from my first comment here (https://github.com/styled-components/styled-components/issues/3800#issuecomment-1247256052)

joshjg avatar Oct 07 '22 01:10 joshjg

I created https://github.com/styled-components/styled-components/pull/3828 as a rollup of the PRs posted thus far.

However I just encountered a new issue:

// baseline
const SA = styled.div``
const A = <SA as="span">hi</SA> // okay

// problem
const Div = ({as, ...props}: ComponentProps<'div'> & {as?: 'div'}) => <div {...props} />
const SB = styled(Div)``
const B = <SB as="span">hi</SB> // error

If the wrapped component supplies an as prop that conflicts with the styled wrapper, it generates a type error:

Type 'string' is not assignable to type 'never'.

I think this is because we're extracting ComponentProps<Target> in multiple places, first into OuterProps and then later in PolymorphicComponentProps. Only the latter omits as. I haven't figured out exactly what needs to change yet.

@probablyup @joshjg Any thoughts on this? I'm getting lost between baseStyled, constructWithOptions, and createStyledComponent

agriffis avatar Oct 11 '22 18:10 agriffis

In my NextJS app (12.3.1) when I upgrade to 6.0.0.beta-3, I get this error message ad infinitum:

TypeError: tslib.__spreadArray is not a function
at Function.templateFunction [as div] (/Users/thomas/bend/web/node_modules/styled-components/dist/styled-components.cjs.js:1602:75)

thomasmost avatar Oct 11 '22 23:10 thomasmost

Is the babel plugin required for v6 / use with TypeScript?

thomasmost avatar Oct 11 '22 23:10 thomasmost

@thomasmost Re tslib, I've seen that too. I just threw in tslib and the problem went away. It would be good to know what we should do or document in styled-components to fix this properly, though.

Re babel plugin, it shouldn't be required except for SSR. And on Next.js there's also the SWC option. See https://styled-components.com/docs/advanced#nextjs

agriffis avatar Oct 12 '22 16:10 agriffis

Beta 4 is now out with significant type improvements: https://github.com/styled-components/styled-components/releases/tag/v6.0.0-beta.4

quantizor avatar Oct 25 '22 09:10 quantizor