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

Declare web component in solid typescript #616

Closed
nemixe opened this issue Aug 23, 2021 · 10 comments
Closed

Declare web component in solid typescript #616

nemixe opened this issue Aug 23, 2021 · 10 comments
Labels
typescript relating to typescript or types

Comments

@nemixe
Copy link

nemixe commented Aug 23, 2021

have been tried implement web component in solid typescript but i dont really know how to declare the component name, it show an error like this.

CleanShot 2021-08-23 at 08 36 54@2x

i have tried to declare it on file declaration.d.ts like this.

CleanShot 2021-08-23 at 08 37 56@2x

is there any way to declare web component name in solid typescript ?, thanks!.

@ryansolid
Copy link
Member

I think the problem is that works on the global namespace and it needs to work on Solid's. I've done it the way posted above in the past but that was back when we were too polluting the global namespace like React.

So perhaps:

declare module "solid-js" {
  namespace JSX {
    interface IntrinsicElements {
      "component1-component": any
    }
  }
}

@nemixe
Copy link
Author

nemixe commented Aug 23, 2021

thanks for your reply. so i've implement it and now it shows different error like this.

CleanShot 2021-08-23 at 11 36 35@2x

this is my declaration.d.ts file look like.
CleanShot 2021-08-23 at 11 38 49@2x

@nemixe
Copy link
Author

nemixe commented Aug 23, 2021

but i found out if i declare it on component file like this.

CleanShot 2021-08-23 at 16 09 12@2x

this works, but i dont know if this is a good practice or not.

@ryansolid ryansolid added the typescript relating to typescript or types label Aug 23, 2021
@ryansolid
Copy link
Member

Honestly, TypeScript differentiating between this confuses me. Anyone with TS experience with custom elements can chime in. @trusktr maybe.

@rturnq
Copy link
Member

rturnq commented Aug 23, 2021

You should be able to perform this module augmentation in a declaration file (.d.ts) which will make it available everywhere in your app. The trick is to also import 'solid-js' in that declaration file. Without the import, the new module declaration clobbers the existing one instead of extending it. Here is an example: https://codesandbox.io/s/solid-counter-forked-ulhhj?file=/my-web-components.d.ts

Please also note codesandbox falls down sometimes dealing with this stuff - reloading usually fixes it.

@nemixe
Copy link
Author

nemixe commented Aug 24, 2021

works perfectly, thanks!.

@nemixe nemixe closed this as completed Aug 24, 2021
@hawkticehurst
Copy link

hawkticehurst commented Jun 1, 2022

Chiming in with a potential improvement on the ideas/code snippets in this thread:

There was a discussion/thread in a WC library called Shoelace on how to use the components in Solid.

As part of that discussion, @justinfagnani (a member of the Lit team at Google) offered the below declaration file snippet as a way to get even better type annotations on web components used in Solid.

I figured out how to get good typings for all custom elements that are added to HTMLElementTagNameMap without having to add each individually to 'solid-js'.JSX.IntrinsicElements and without using any for the type.

declare module 'solid-js' {
  namespace JSX {
    type ElementProps<T> = {
      // Add both the element's prefixed properties and the attributes
      [K in keyof T]: Props<T[K]> & HTMLAttributes<T[K]>;
    }
    // Prefixes all properties with `prop:` to match Solid's property setting syntax
    type Props<T> = {
      [K in keyof T as `prop:${string & K}`]?: T[K];
    }
    interface IntrinsicElements extends ElementProps<HTMLElementTagNameMap> {
    }
  }
}

You can see in the Solid playground that an element with foo: number causes an error with a binding of prop:foo={'hello'}, which is what we want:

Solid Playground Link

^(Link to Justin's comment for more context)

It's also worth noting, however, that this will only work for web component libraries that add their components to the global HTMLElementTagNameMap interface as demonstrated in the above Solid playground link. This is something that Shoelace does for its components, but you'll want to check your desired component library for this addition.

Hope it helps anyone still passing by on this thread!

@AlexErrant
Copy link
Contributor

If you extend 'solid-js'.Component (instead of HTMLElement as above), here's some half-working code:

declare module "solid-js" {
  namespace JSX {
    type ElementProps<T> = {
      [K in keyof T]: T[K] extends Component<infer P> ? P : never
    }

    interface IntrinsicElements extends ElementProps<HTMLElementTagNameMap> {}
  }
}

Unfortunately this code does not error if you pass props to a component that has no props, like function MyComp(): JSX.Element { ... }. Unfortunately I'm not good enough at TypeScript to figure out the solution. Some thoughts on where I gave up:

The default generic on Component is {}, which I can't differentiate from a populated prop using conditional types. In other words:

    type ElementProps<T> = {
      [K in keyof T]: T[K] extends Component<infer P>
        ? P extends Record<string, never>
          ? boolean // this is never hit
          : P
        : never // though this is hit, which correctly yields errors if, say, you pass a string to an number prop
    }

For now I think I'll just have two HTMLElementTagNameMaps - one for Components with props, and one for Components without props. I haven't tried it yet though.

wridgeu added a commit to wridgeu/sap-cap-solidjs that referenced this issue Jan 11, 2023
extract it from index.tsx
allow for extension by importing solid-js itself to not overwrite but extend and make HTMLAttributes known
see: solidjs/solid#616 (comment) and https://github.com/solidjs/solid/blob/89baf1206a1df27ab5a666b6c31729fd1505e341/packages/solid/h/jsx-runtime/src/jsx.d.ts
@nilshelmig
Copy link

@ryansolid Any plans or information to support this in solidjs? Or at least a documentation note, that using web components with typescript requires this?

@ryansolid
Copy link
Member

There was a documentation note at one point about what I posted above. But, looking now it doesn't seem to have made it to the new Docs. So I think there could be a note about how to declare web components in the TS section.

Opened an issue: solidjs/solid-docs#823

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

No branches or pull requests

6 participants