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

Typing errors when using @headlessui/react with preact #4072

Open
kurtbuilds opened this issue Jul 14, 2023 · 2 comments
Open

Typing errors when using @headlessui/react with preact #4072

kurtbuilds opened this issue Jul 14, 2023 · 2 comments
Labels

Comments

@kurtbuilds
Copy link

kurtbuilds commented Jul 14, 2023

This repo contains a very basic react app, using a Disclosure component from @headlessui/react:

https://github.com/kurtbuilds/react-headlessui.git

Run tsc on that repo, and no errors are reported.

This identical project is using preact. The app functions as intended, but typescript (incorrectly) reports errors:

https://github.com/kurtbuilds/preact-headlessui-issue.git

The (first) error is Type 'string' is not assignable to type '(bag: DisclosureRenderPropArg) => string'. on the className property of the Disclosure jsx component.

Brief background on headlessui: the headlessui components are generic on the tag property (e.g. it renders in HTML as a <nav> element if you use the property as="nav"). Accordingly, the type is generic on that, and for some reason, I think those generics aren't working with preact right now. Following the full logic chain from headlessui/react:

Disclosure has the type defined here: https://github.com/tailwindlabs/headlessui/blob/076b03cf491629b1930531c4ca616902be6c1688/packages/%40headlessui-react/src/components/disclosure/disclosure.tsx#L430

interface ComponentDisclosure extends HasDisplayName {
  <TTag extends ElementType = typeof DEFAULT_DISCLOSURE_TAG>(
    props: DisclosureProps<TTag> & RefProp<typeof DisclosureFn>
  ): JSX.Element
}

and DisclosureProps ultimately gets the className property from ClassNameOverride in the Props type here: https://github.com/tailwindlabs/headlessui/blob/076b03cf491629b1930531c4ca616902be6c1688/packages/%40headlessui-react/src/types.ts#L48

If I manually test out those types, their logic is definitely working (also confirmed by it working in React), so I think the issue is something about the generic not working correctly.


I tried manually editing the ClassNameOverride type to see if there are any errors that crop up once this one is fixed. Unforunately, there's another error hidden behind this one.

TS2322: Type '{ children: ({ open }: { open: boolean; }) => Element; as: string; className: string; }' is not assignable to type 'IntrinsicAttributes & CleanProps<string, never> & OurProps<string, DisclosureRenderPropArg> & { ...; } & { ...; } & { ...; }'.   Type '{ children: ({ open }: { open: boolean; }) => Element; as: string; className: string; }' is not assignable to type 'CleanProps<string, never>'.     Property 'children' is incompatible with index signature.       Type '({ open }: { open: boolean; }) => JSXInternal.Element' is not assignable to type 'never'.

Fortunately, I think this is a similar issue to the previous one. The stated error is about the children of the component (the child being a function ({open}) => JSXInternal.Element) is not assignable to never, which appears to come from a generic parameter from CleanProps. And I think that generic should be taking a value, rather than be never-valued.

To confirm that latter point, if you make a typo in the function in the react version of the project, you'll get an error: TS2339: Property 'ope' does not exist on type '{ open: boolean; }'., which confirms that the expected value for children of the Disclosure component, in the react version, does get correctly typed as ({open} => JSXInternal.Element.

I've managed to workaround this issue for now by remapping the types of the components as any:

import {
    Disclosure as HDisclosure,
} from '@headlessui/react'

export const Disclosure: any = HDisclosure;

but obviously that eliminates any benefit from using typescript. If there are better workarounds until this gets solved, I'm curious to hear them.


I originally discussed this issue in #4068

@pm0u
Copy link

pm0u commented Apr 3, 2024

I am also running into this issue Preact 10.19.6 with the Tab component and associated components.

It seems to be something with the as prop on these components, which allows them to render as a dom element of your choosing.

  • When I add as="section" (or any valid DOM element) the expected type for children becomes string and Element is not valid
  • When I add as="section" (or any valid DOM element) the expected type for className becomes (bag: TabsRenderPropArg) => string'
  • Without as, the expected type for className is any however it is defined as string | (bag: TabsRenderPropArg) => string'
  • Without as, Element children do not throw a type error

There seems to be some issue resolving the conditional types generated by headlessui

I did find that react was being installed until i used the --legacy-peer-deps flag with npm i but the issue persists.

@bagou4502
Copy link

Same issue on my side with Preact 10.20.1 and Transition component of headless ui 1.7.19

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants