Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issues spreading omitted props onto components #3313

Merged
merged 4 commits into from
Jun 24, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,6 @@ function TransitionChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_
leaveFrom,
leaveTo,

// @ts-expect-error
...theirProps
} = props as typeof props
let container = useRef<HTMLElement | null>(null)
Expand Down Expand Up @@ -444,6 +443,8 @@ function TransitionChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_
className:
classNames(
// Incoming classes if any
// @ts-expect-error: className may not exist because not
// all components accept className (but all HTML elements do)
theirProps.className,

// Apply these classes immediately
Expand Down Expand Up @@ -498,7 +499,6 @@ function TransitionRootFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_C
props: TransitionRootProps<TTag>,
ref: Ref<HTMLElement>
) {
// @ts-expect-error
let { show, appear = false, unmount = true, ...theirProps } = props as typeof props
let internalTransitionRef = useRef<HTMLElement | null>(null)
let requiresRef = shouldForwardRef(props)
Expand Down Expand Up @@ -610,10 +610,8 @@ function ChildFn<TTag extends ElementType = typeof DEFAULT_TRANSITION_CHILD_TAG>
return (
<>
{!hasTransitionContext && hasOpenClosedContext ? (
// @ts-expect-error This is an object
<TransitionRoot ref={ref} {...props} />
) : (
// @ts-expect-error This is an object
<InternalTransitionChild ref={ref} {...props} />
)}
</>
Expand Down
6 changes: 4 additions & 2 deletions packages/@headlessui-react/src/utils/render.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -424,9 +424,11 @@ describe('Features.Static | Features.RenderStrategy', () => {
}

// TODO: Can we "legit" test this? 🤔
it('should result in a typescript error', () => {
it.skip('should result in a typescript error', () => {
testRender(
// @ts-expect-error static & unmount together are incompatible
// Properly setting up the types for this causes way more problems than it solves.
// Omit<…> has issues for instance when spreading the rest of the props on the component.
// @!ts-expect-error static & unmount together are incompatible
thecrypticace marked this conversation as resolved.
Show resolved Hide resolved
<Dummy show={false} static unmount>
Contents
</Dummy>
Expand Down
18 changes: 11 additions & 7 deletions packages/@headlessui-react/src/utils/render.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import {
type ReactElement,
type Ref,
} from 'react'
import type { Expand, Props, XOR, __ } from '../types'
import type { Expand, Props } from '../types'
thecrypticace marked this conversation as resolved.
Show resolved Hide resolved
import { classNames } from './class-names'
import { match } from './match'

Expand Down Expand Up @@ -40,17 +40,21 @@ export enum RenderStrategy {
Hidden,
}

type UnionToIntersection<T> = (T extends any ? (x: T) => any : never) extends (x: infer R) => any
? R
: never

type PropsForFeature<
TPassedInFeatures extends RenderFeatures,
TForFeature extends RenderFeatures,
TProps,
> = {
[P in TPassedInFeatures]: P extends TForFeature ? TProps : __
}[TPassedInFeatures]
> = TPassedInFeatures extends TForFeature ? TProps : {}

export type PropsForFeatures<T extends RenderFeatures> = XOR<
PropsForFeature<T, RenderFeatures.Static, { static?: boolean }>,
PropsForFeature<T, RenderFeatures.RenderStrategy, { unmount?: boolean }>
export type PropsForFeatures<T extends RenderFeatures> = Expand<
UnionToIntersection<
| PropsForFeature<T, RenderFeatures.Static, { static?: boolean }>
| PropsForFeature<T, RenderFeatures.RenderStrategy, { unmount?: boolean }>
>
>

export function render<TFeature extends RenderFeatures, TTag extends ElementType, TSlot>({
Expand Down
Loading