#Any example of a Polymorphic components with typescript in Qwik?

39 messages · Page 1 of 1 (latest)

viscid harness
#

This is how far I have gotten:

type AsProp<T extends keyof JSX.IntrinsicElements> = {
    as?: T
}

export type DialogTriggerProps<T extends keyof JSX.IntrinsicElements> = AsProp<T> & JSX.IntrinsicElements[T]

const DialogTrigger = component$<DialogTriggerProps<"button">>(({ as: Tag = "button", ...props }) => {

Problems:
Only accepts "button" dont know how to type it with compoennt$<>
I would like to accept Component<Props> aswell

sour citrus
viscid harness
#

meaning you would need to always set a value for as to get some typings

sour citrus
#

I am sure I have used his method with default value, I'll check my code and get back to you

sour citrus
#

Hey check if this will help:

#
export type TooltipProps<C extends keyof QwikIntrinsicElements = 'div'> = QwikIntrinsicElements[C] & {
  as?: C,
  content?: string,
  placement?: Placement,
  maxWidth?: string,
  maxHeight?: string,
  sticky?: boolean,
  clickable?: boolean,
  withArrow?: boolean,
  light?: boolean,
  disableTooltip?: boolean
}```
#
export type TooltipWrapElement = 'div' | 'a' | 'span' | 'button' | 'ul' | 'li' | 'i' | 'b' | 'em' | 'strong';
#
export const Tooltip = component$<TooltipProps<TooltipWrapElement>>((props) => {});```
viscid harness
#

thanks ill give it a try

fallen pelican
#

Do you guys have issues with <Slot /> as well when you try to do polymorphic elements like this?

sour citrus
fallen pelican
sour citrus
#

Ouf that's a mouthful, maybe if you share a line or two of code I can take a look later 🙂

fallen pelican
#

That's if I use keyof HTMLElements as the passed generic

#

if I use keyof QwikIntrinsicElements I get this instead

#

If I make and if statement that says if element is a div, then I can return the element, however doing this for each possible outcome, kinda feels like going against the idea of a component being polymorphic

sour citrus
#

What elements are included in QwikElemnts type, is it a qwik internal type (I'm away from my computer)

#

If this type includes elements that cannot have children it'll make sense why the slot cannot be a child of the component

fallen pelican
sour citrus
#

Ah so all possible html elements, that is probably the reason of the types incompatibility. Check out my comment above, the elements should be somewhat compatible and should have the possibility to have children

fallen pelican
#

So if I attempt to specify my own possible elements, kinda like you did, I get this instead

sour citrus
#

I'll get to my PC later this evening and will check what exactly we are doing. If you wish you can share more code in new thread or DM me

fallen pelican
warm glacier
#

Yeah, i think you need to omit the children. IIRC I do something like this.

import type { QwikIntrinsicElements } from '@builder.io/qwik';

export type AnyTag = keyof QwikIntrinsicElements;

export type BaseProps<Tag extends AnyTag> = Omit<QwikIntrinsicElements[Tag], 'children'> & {
  as?: AnyTag
};

export type MyComponentProps<Tag extends AnyTag> = BaseProps<Tag>;
#

and then use it something like

export const MyComponent = component$<MyComponentProps<typeof 'button'>>((props) => {})
fallen pelican
#

Thanks for pitching in @warm glacier, unfortunately this doesn't solve the errors I'm getting. I don't know if it's because I'm passing more props than the as one in your example. But something is in the way. I get union too complex error, element not assignable to type undefined or type has no call signatures.

warm glacier
warm glacier
#

Don't ask me where I learned this, I don't remember 🙂

const Component = (element || 'div') as string | Component<Record<string, unknown>>;
#

also in your example it will always be element since it's a required prop.

fallen pelican
#

I’ll give it a shot, it does seems a bit random, but if it satisfies the typescript gods, then it’s good enough for me 🥹🙏🏼

fallen pelican
#

I'm getting no errors at least, so fingers crossed this was the golden touch needed. Once again thank you so much @warm glacier

sour citrus
#
 {/* @ts-ignore */}
      <TagName {...rest}>
        <Slot></Slot>
      </TagName>
#

This little bugger is needed (ts-ignore) because you will never have a 100% type overlap between different html element and their event signatures

fallen pelican
#

I did not have any type errors... but I didn't get it to work :/