-
-
Notifications
You must be signed in to change notification settings - Fork 2k
Description
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