blaumeise20/template-jsx

HTML element typings

ddprrt opened this issue · 9 comments

Alvin, this is fantastic! Just took a quick peek at it and there's so much good stuff in it:

  1. Declarative Conditionals! Fantastic!
  2. The use of symbols is ace! I rarely see symbols in the wild, but what you did with them just makes so much sense! 👏

What I found out:

  1. Let me guess if you activate noImplictAny TypeScript throws a couple of errors at you for the use of JSX? I've written something similar for regular DOM nodes a while ago: https://codesandbox.io/s/lesson-4647-jsx-9vf1b?file=/src/index.tsx -- and what I needed to make typings work is to extend the JSX namespace and provide intrinsic elements (see lines 109ff). I make use of the HTMLElementTagNameMap which is part of the dom lib. I don't think the entire dom lib should be referred to when using a server-side JSX implementation, but maybe you can refer to this particular type or simply copy it from the TypeScript libs.
  2. If I see it correctly, you create your own HTML Wrapper (doctype, html, head, etc.). Did you look at how NextJS Allows to declaratively extend fields in there? https://nextjs.org/docs/api-reference/next/head -- this might be something that might be interesting for you!

Cheers, great work!

Thanks for your feedback! I've implemented the second thing now (at least you can add elements to the head). I already tried to do something with the first one, but I had problems typing the object { req, res }. As you can see here, it is made for express.js servers. The problem is now that I don't want to make express a dependency, because maybe some people don't want to use express when using this package. So how do I correctly type this with the express.Request and express.Response type?

Cool!

You have a couple of possibilities.

  1. Type with any. This is the wildcard and you can do everything with it. You just have to trust your users that they pass the correct objects in (they can...)
  2. Install @types/express as a dependency, and import express.Response etc with import type { Response } from "express" -- TypeScript allows you only to import types, nothing more.
  3. Define @types/express and express as peerDependencies. So you can work with them when developing, and your users have to install both express and @types/express on their own if they want to use it with Express. Read more on that here: https://docs.npmjs.com/cli/v7/configuring-npm/package-json#peerdependencies

Cheers!

So I added @types/express as a dependency because when other people use this package with TypeScript (one intended use case) and the types are not installed, TypeScript will give an error that is not made by them. So to make sure that no error exists, I added the types but not the core library itself.

There is one problem I have. When I use noImplicitAny TypeScript tells me that it can't find the interface JSX.IntrinsicElements but I have declared it. How could I solve that problem?

So to make sure that no error exists, I added the types but not the core library itself.

That's perfectly fine!

There is one problem I have. When I use noImplicitAny TypeScript tells me that it can't find the interface JSX.IntrinsicElements but I have declared it. How could I solve that problem?

Where did you declare it? It might be that you need to export this type ... but I'm not sure. Maybe you can upload your current source in a branch or similar so I can check :)

I pushed the code I wrote to GitHub now. Where do you mean I have to export the type? Something like this?

export declare namespace JSX {}

I already tried that but it still didn't work.

Okidoki... I think I got it :-) I installed your library and tried it out in a new project... there's just a couple of things to change that should make it work.

  1. The current dist/index.d.ts does not include the JSX typings. Maybe that's just a missing build away
  2. As you already found out, an export statement is necessary. export declare namespace JSX { ... } is the way to go
  3. Add a reference to your types in package.json:
{
 ...
 "types": "./dist/index.d.ts",
}

This will let TypeScript pick up any extra types through usage

  1. snip don't do this :D

Hope this helps!

Hm... wait a second... instead of doing point 4, try

export declare namespace JSX {
    type OurIntrinsicElements = {
        [P in keyof HTMLElementTagNameMap]: Partial<HTMLElementTagNameMap[P]>;
    };

    interface IntrinsicElements extends OurIntrinsicElements {}

    interface Element extends HTMLElement {}
}
    

As your JSX declaration.
This should give you two things:

  1. Correct typings for HTML! Which means that you get things like ARIA roles, attributes for HTML elements, etc. for free
  2. No changes in your actual code.

Yes, this is nice :)

image

I somehow managed to do it now, but it is not optimal. You don't have the HTML suggestions and errors and the type for elements is also any, but you don't get errors now. I will look into it later but close this issue now.