Skip to content
New issue

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

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

Already on GitHub? # to your account

Example of TypeScript Types in file index.d.ts for a web-component. #173

Closed
riccardoscalco opened this issue Jul 20, 2021 · 7 comments
Closed
Labels
help typescript Applies to TypeScript support

Comments

@riccardoscalco
Copy link
Contributor

Hi, recently I wrote a web component with hybrids. The package score in skypack.dev shows that TypeScript Types are missing in the package.

I am very new to TypeScript and I do not know exactly how to create the index.d.ts file for the web component. I found this page in hybrids docs, where there is an example of how to use TypeScript with hybrids.

However, I prefer to keep the code in plain JS and create the file index.d.ts for the user-base that works with TypeScript.

Could you please provide an example of the file index.d.ts related to a web component created with hybrids?
Thanks in advance.

@smalluban
Copy link
Contributor

Hi @riccardoscalco. Your question is more general, and not strictly related to hybrids, but to defining custom elements for the TS. I suppose, that there is no one the best way to do that, but I can recommend looking for some examples. One of the time elements from GitHub produces following d.ts file:

export default class LocalTimeElement extends ExtendedTimeElement {
    attributeChangedCallback(attrName: string, oldValue: string, newValue: string): void;
    getFormattedDate(): string | undefined;
}
declare global {
    interface Window {
        LocalTimeElement: typeof LocalTimeElement;
    }
    interface HTMLElementTagNameMap {
        'local-time': LocalTimeElement;
    }
}

The above definition assumes, that this custom element is also registered in window.LocalTimeElement. For proper recongnision with calls like document.createElement("local-time") they put a tag name into the special HTMLElementTagNameMap.

For the component built with hybrids, follow typescript guides for putting properties into the class, and create something like this:

class MyElement extends HTMLElement {
  propOne: string;
  propTwo: string;
}

declare global {
    interface Window {
        MyElement: typeof MyElement; // if you register your element in global scope
    }
    interface HTMLElementTagNameMap {
        'my-element': LocalTimeElement;
    }
}

There is also a tool https://github.com/runem/web-component-analyzer, which describes how you can add comments/metadata for better IDE completion.

@smalluban smalluban added the help label Jul 20, 2021
@smalluban
Copy link
Contributor

I'm not sure, but it might be required to add a module statement wrapper, as you expose it as an npm module:

declare module "@nextbitlabs/trend-line" {
  ...
}

For testing the best way is to set up a simple project, which uses TS and import your module by the relative path from the disk npm i ../trend-line to check if d.ts is correct.

@riccardoscalco
Copy link
Contributor Author

Thanks for the precious suggestions, I give it a try!

@smalluban
Copy link
Contributor

Share your result when it will be ready :)

@smalluban smalluban added the typescript Applies to TypeScript support label Jul 23, 2021
@riccardoscalco
Copy link
Contributor Author

An update: I managed to automatically generate file index.d.ts from a slightly modified version of the example in the docs. Note that I used import from URL and plain JS similarly to the mentioned web-component I am working on.

File index.ts is the following:

// @ts-ignore
import { define, html } from 'https://cdn.skypack.dev/hybrids@6';

function increaseCount(host) {
  host.count += 1;
}

export const SimpleCounter = {
  count: 0,
  render: ({ count }) => html`
    <button onclick="${increaseCount}">
      Count: ${count}
    </button>
  `,
};

define('simple-counter', SimpleCounter);

The automatically generated index.d.ts is:

export declare const SimpleCounter: {
    count: number;
    render: ({ count }: {
        count: any;
    }) => any;
};

I am not sure this index.d.ts is useful at all.

@smalluban
Copy link
Contributor

Your automatically generated index.d.ts won't be useful for code completion. It defines the hybrids definition, but users of your library interact with the custom element. You need an interface of your properties and extend global HTMLElementTagNameMap to allow the TS server to find the definition when using document.createElement("my-element") APIs.

Try to follow what I wrote in the last comments.

@smalluban
Copy link
Contributor

Feel free to re-open if you need more help with the subject.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
help typescript Applies to TypeScript support
Development

No branches or pull requests

2 participants