styled-components v6 beta feedback
Starting a new thread for issues related to beta npm tag.
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.
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
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
These types are pretty complicated to say the least, will keep working on them
@probablyup I've been fiddling with some stuff, specifically:
- kill
BaseExtensibleObject(and useDict<any>explicitly in places that need that kind of thing, wheretype Dict<T> = {[k: string]: T}) - rename
ExtensibleObjecttoExecutionPropssince it's essentially a partialExecutionContext - 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.
PRs would be great, thank you 😄
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 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:
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.)
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.

const StyledButton = styled.button``;
const Example2 = styled.div`
${StyledButton} {
color: blue;
}
`;
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
@container rules ONLY work if no cascade is applied.
https://codesandbox.io/s/trusting-mahavira-pf8pnx?file=/src/App.tsx
@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?
@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 Thanks for the clarification. Looks like this will depend on a change in stylis, see https://github.com/thysultan/stylis/issues/303
@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.
Actually I think it was this one that looked attractive: https://github.com/mmkal/expect-type
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
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
Does this mean that the default validator inside
shouldForwardPropis dropped ?
Yes, see 6baaea48
Here are a couple confusing things I'm seeing in beta 3:
- TS error trying to destructure theme from props, see
XandYin sandbox - Styled component props seems to lack
as, hover overZPropsin same sandbox
Sandbox link: https://codesandbox.io/s/styled-components-v6-forked-3ehn9o
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.
@probablyup I think that #3825 fixes the as problem.
@probablyup and #3826 just might fix the interpolations problem
@agriffis @probablyup Opened #3827 to fix the issues from my first comment here (https://github.com/styled-components/styled-components/issues/3800#issuecomment-1247256052)
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
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)
Is the babel plugin required for v6 / use with TypeScript?
@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
Beta 4 is now out with significant type improvements: https://github.com/styled-components/styled-components/releases/tag/v6.0.0-beta.4