Skip to content

Commit a593d19

Browse files
Fix issues spreading omitted props onto components (#3313)
* Simplify props types wip wip * Remove unused types * Remove test it’s no longer relevant * Update changelog
1 parent d60ed6a commit a593d19

File tree

5 files changed

+16
-39
lines changed

5 files changed

+16
-39
lines changed

packages/@headlessui-react/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- Nothing yet!
10+
### Fixed
11+
12+
- Fix issues spreading omitted props onto components ([#3313](https://github.com/tailwindlabs/headlessui/pull/3313))
1113

1214
## [2.1.0] - 2024-06-21
1315

packages/@headlessui-react/src/components/transition/transition.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,6 @@ function TransitionChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_
318318
leaveFrom,
319319
leaveTo,
320320

321-
// @ts-expect-error
322321
...theirProps
323322
} = props as typeof props
324323
let container = useRef<HTMLElement | null>(null)
@@ -444,6 +443,8 @@ function TransitionChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_
444443
className:
445444
classNames(
446445
// Incoming classes if any
446+
// @ts-expect-error: className may not exist because not
447+
// all components accept className (but all HTML elements do)
447448
theirProps.className,
448449

449450
// Apply these classes immediately
@@ -498,7 +499,6 @@ function TransitionRootFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_C
498499
props: TransitionRootProps<TTag>,
499500
ref: Ref<HTMLElement>
500501
) {
501-
// @ts-expect-error
502502
let { show, appear = false, unmount = true, ...theirProps } = props as typeof props
503503
let internalTransitionRef = useRef<HTMLElement | null>(null)
504504
let requiresRef = shouldForwardRef(props)
@@ -610,10 +610,8 @@ function ChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG>
610610
return (
611611
<>
612612
{!hasTransitionContext && hasOpenClosedContext ? (
613-
// @ts-expect-error This is an object
614613
<TransitionRoot ref={ref} {...props} />
615614
) : (
616-
// @ts-expect-error This is an object
617615
<InternalTransitionChild ref={ref} {...props} />
618616
)}
619617
</>

packages/@headlessui-react/src/types.ts

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,6 @@ import type { JSXElementConstructor, ReactElement, ReactNode } from 'react'
22

33
export type ReactTag = keyof JSX.IntrinsicElements | JSXElementConstructor<any>
44

5-
// A unique placeholder we can use as a default. This is nice because we can use this instead of
6-
// defaulting to null / never / ... and possibly collide with actual data.
7-
// Ideally we use a unique symbol here.
8-
let __ = '1D45E01E-AF44-47C4-988A-19A94EBAF55C' as const
9-
export type __ = typeof __
10-
115
export type Expand<T> = T extends infer O ? { [K in keyof O]: O[K] } : never
126

137
export type PropsOf<TTag extends ReactTag> = TTag extends React.ElementType
@@ -55,15 +49,4 @@ export type Props<
5549
ClassNameOverride<TTag, TSlot> &
5650
Overrides
5751

58-
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never }
59-
export type XOR<T, U> = T | U extends __
60-
? never
61-
: T extends __
62-
? U
63-
: U extends __
64-
? T
65-
: T | U extends object
66-
? (Without<T, U> & U) | (Without<U, T> & T)
67-
: T | U
68-
6952
export type EnsureArray<T> = T extends any[] ? T : Expand<T>[]

packages/@headlessui-react/src/utils/render.test.tsx

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -423,16 +423,6 @@ describe('Features.Static | Features.RenderStrategy', () => {
423423
)
424424
}
425425

426-
// TODO: Can we "legit" test this? 🤔
427-
it('should result in a typescript error', () => {
428-
testRender(
429-
// @ts-expect-error static & unmount together are incompatible
430-
<Dummy show={false} static unmount>
431-
Contents
432-
</Dummy>
433-
)
434-
})
435-
436426
// To avoid duplication, and to make sure that the features tested in isolation can also be
437427
// re-used when they are combined.
438428
testStaticFeature(Dummy)

packages/@headlessui-react/src/utils/render.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
type ReactElement,
1212
type Ref,
1313
} from 'react'
14-
import type { Expand, Props, XOR, __ } from '../types'
14+
import type { Expand, Props } from '../types'
1515
import { classNames } from './class-names'
1616
import { match } from './match'
1717

@@ -40,17 +40,21 @@ export enum RenderStrategy {
4040
Hidden,
4141
}
4242

43+
type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any
44+
? R
45+
: never
46+
4347
type PropsForFeature<
4448
TPassedInFeatures extends RenderFeatures,
4549
TForFeature extends RenderFeatures,
4650
TProps,
47-
> = {
48-
[P in TPassedInFeatures]: P extends TForFeature ? TProps : __
49-
}[TPassedInFeatures]
51+
> = TPassedInFeatures extends TForFeature ? TProps : {}
5052

51-
export type PropsForFeatures<T extends RenderFeatures> = XOR<
52-
PropsForFeature<T, RenderFeatures.Static, { static?: boolean }>,
53-
PropsForFeature<T, RenderFeatures.RenderStrategy, { unmount?: boolean }>
53+
export type PropsForFeatures<T extends RenderFeatures> = Expand<
54+
UnionToIntersection<
55+
| PropsForFeature<T, RenderFeatures.Static, { static?: boolean }>
56+
| PropsForFeature<T, RenderFeatures.RenderStrategy, { unmount?: boolean }>
57+
>
5458
>
5559

5660
export function render<TFeature extends RenderFeatures, TTag extends ElementType, TSlot>({

0 commit comments

Comments
 (0)