Skip to content

Commit 8aacec3

Browse files
committed
Fix TypeScript error when writing higher order components while using Emotion's JSX namespace
1 parent 3c19ce5 commit 8aacec3

File tree

3 files changed

+76
-8
lines changed

3 files changed

+76
-8
lines changed

.changeset/nervous-pigs-reflect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@emotion/react': patch
3+
---
4+
5+
Fix TypeScript error when writing higher order components while using `@emotion/react` `jsx` pragma/`jsxImportSource`

packages/react/src/jsx-namespace.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ type IsPreReact19 = 2 extends Parameters<React.FunctionComponent<any>>['length']
66
? true
77
: false
88

9-
type WithConditionalCSSProp<P> = 'className' extends keyof P
10-
? string extends P['className' & keyof P]
11-
? { css?: Interpolation<Theme> }
12-
: {}
13-
: {}
9+
type WithConditionalCSSProp<P> =
10+
| (P extends unknown
11+
? 'className' extends keyof P
12+
? string extends P['className' & keyof P]
13+
? { css?: Interpolation<Theme> }
14+
: {}
15+
: {}
16+
: {})
17+
| {}
1418

1519
// unpack all here to avoid infinite self-referencing when defining our own JSX namespace for the pre-React 19 case
1620

@@ -91,9 +95,8 @@ export namespace EmotionJSX {
9195
export interface ElementChildrenAttribute
9296
extends ReactJSXElementChildrenAttribute {}
9397

94-
export type LibraryManagedAttributes<C, P> = P extends unknown
95-
? WithConditionalCSSProp<P> & ReactJSXLibraryManagedAttributes<C, P>
96-
: never
98+
export type LibraryManagedAttributes<C, P> = WithConditionalCSSProp<P> &
99+
ReactJSXLibraryManagedAttributes<C, P>
97100

98101
export interface IntrinsicAttributes extends ReactJSXIntrinsicAttributes {}
99102
export interface IntrinsicClassAttributes<T>

packages/react/types/tests.tsx

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,3 +255,63 @@ const anim1 = keyframes`
255255
// $ExpectError
256256
;<WithOptionalUndefinedClassName css={{ color: 'hotpink' }} />
257257
}
258+
259+
{
260+
const withSomething = <Props extends object>(
261+
SomeComponent: (props: Props & { something: string }) => React.ReactNode
262+
) => {
263+
return (props: Props) => {
264+
return <SomeComponent something="something" {...props} />
265+
}
266+
}
267+
const RendersSomething = withSomething(props => <div>{props.something}</div>)
268+
;<RendersSomething />
269+
270+
const WithSomeStyle = <Props extends { className?: string }>(
271+
SomeComponent: (props: Props) => React.ReactNode
272+
) => {
273+
return (props: Props) => {
274+
return (
275+
<SomeComponent
276+
{...props}
277+
// this expect type is important over this just not erroring because an excess property in this case is allowed
278+
// but this lets us roughly test that `css` is in autocomplete/etc.
279+
// $ExpectType Interpolation<Theme>
280+
css={{ direction: 'rtl' }}
281+
/>
282+
)
283+
}
284+
}
285+
const Something = WithSomeStyle((props: { className?: string }) => null)
286+
;<Something css={{ color: 'green' }} />
287+
;<Props extends { className?: string }>(
288+
SomeComponent: (props: Props) => React.ReactNode
289+
) => {
290+
return (props: Props) => {
291+
return (
292+
<SomeComponent
293+
{...props}
294+
css={{
295+
// ideally this would error but it also doesn't matter much
296+
// (this particular css={{ direction: 'does not exist' }} does error when used normally)
297+
direction: 'does not exist'
298+
}}
299+
/>
300+
)
301+
}
302+
}
303+
;<Props extends object>(SomeComponent: (props: Props) => React.ReactNode) => {
304+
return (props: Props) => {
305+
return (
306+
<SomeComponent
307+
{...props}
308+
// this isn't an error because excess properties is a best effort thing in ts etc.
309+
// (and in this case with a generic, not erroring here makes a lot of sense)
310+
// but expecting this type is a way to test that `css` isn't in autocomplete/etc.
311+
// $ExpectType {}
312+
css={{}}
313+
/>
314+
)
315+
}
316+
}
317+
}

0 commit comments

Comments
 (0)