TS2590 in styled-components' own .d.ts since 6.5.0 when HTMLAttributes has a template-literal index signature

Author: binhpvCreated Aug 12, 2026Updated Aug 15, 2026

Since 6.5.0, styled-components' own declaration files fail to type-check with TS2590 when React.HTMLAttributes carries a template-literal index signature — the common augmentation used to allow arbitrary data-* attributes.

Because the errors are located inside node_modules/styled-components/dist/*.d.ts, any project that does not set skipLibCheck: true cannot compile at all.

node_modules/styled-components/dist/constructors/styled.d.ts(13,75): error TS2590: Expression produces a union type that is too complex to represent.
node_modules/styled-components/dist/types.d.ts(169,13): error TS2590: Expression produces a union type that is too complex to represent.

Minimal reproduction

Three files, no styled component ever declared — a bare import is enough, so this is purely declaration-level.

src/react-aug.d.ts

typescript
import "react";

declare module "react" {
	interface HTMLAttributes<T> {
		[dataAttr: `data-${string}`]: string | undefined;
	}
}

src/index.tsx

typescript
import "styled-components";

tsconfig.json

json
{
	"compilerOptions": {
		"jsx": "react-jsx",
		"lib": ["DOM", "ES2025"],
		"module": "NodeNext",
		"moduleResolution": "NodeNext",
		"target": "ES2025",
		"strict": true,
		"noEmit": true,
		"skipLibCheck": false
	},
	"include": ["src"]
}

Versions affected

Same repro, only the styled-components version changed:

version TS2590 count
6.4.1 0
6.4.2 0
6.4.3 0
6.4.4 0
6.5.0 2
6.5.1 2
6.5.2 2

Introduced in 6.5.0 and still present in 6.5.2.

Environment: TypeScript 6.0.3, React 19.2.6, @types/react 19.2.17, macOS.

Possible cause

6.5.0 moved the inline-style CSS-custom-property widening into TargetProps, so styled.d.ts:13 now applies it eagerly for every tag:

typescript
declare const styled: typeof baseStyled & { [E in SupportedHTMLElements]: StyledInstance<"web", E, TargetProps<"web", E>>; };

IntrinsicProps<T> resolves to WithCSSVars<React.JSX.IntrinsicElements[T]>, whose Omit<P, 'style'> is Pick<P, Exclude<keyof P, 'style'>>. When keyof P includes a template-literal key, that Pick appears to be what pushes the union past the complexity limit once it is instantiated across all ~170 elements.

The trigger is specifically a template-literal key, not an index signature in general. Swapping the augmentation to a plain string index signature is fine on every 6.5.x:

augmentation on HTMLAttributes 6.5.0 6.5.1 6.5.2
[dataAttr: `data-${string}`]: string | undefined 2 2 2
[dataAttr: string]: unknown 0 0 0

(To be clear, the plain-string form was never broken — that row is a contrast, not a regression that 6.5.2 fixed.)

That contrast may still be useful, because the guard added to OverrideStyle in 6.5.2 keys off string exactly:

typescript
type OverrideStyle<P extends BaseObject> = P extends unknown ? string extends keyof P ? P : 'style' extends keyof P ? WithCSSVars<P> : P : never;

A template-literal key does not satisfy string extends keyof P, so such a prop bag falls through to WithCSSVars. If that guard is the intended escape hatch for index-signature-bearing targets, it may need to recognise template-literal keys too.

Impact and workaround

skipLibCheck: true clears it in a small project, but that is a broad concession for a library-side type error, and it does not fully solve the problem in a real codebase: with skipLibCheck on, the same TS2590 reappears in user code wherever a styled component is picked conditionally, e.g.

typescript
// TS2590 at the JSX call site
const Wrapper = props.tiny ? StyledTinyWrapper : StyledWrapper;
return <Wrapper />;

Annotating those away (const Wrapper: typeof StyledWrapper = …) works, but has to be repeated per site.

Happy to test a patch against our codebase (a ~3,300-test component library) if that would help.

Source: styled-components/styled-components