preact icon indicating copy to clipboard operation
preact copied to clipboard

FunctionComponent should allow returning VNode[] for HTM

Open reinhrst opened this issue 1 year ago • 1 comments

  • [ ] Check if updating to the latest Preact version resolves the issue

Describe the bug Trying to use typing (tsserver with JSDoc), with Preact/HTM, I get a type-mismatch when I try to annotate my Function Components:

Type '() => VNode<any> | VNode<any>[]' is not assignable to type 'FunctionComponent<{}>'.
  Type 'VNode<any> | VNode<any>[]' is not assignable to type 'VNode<any>'.
     Type 'VNode<any>[]' is missing the following properties from type 'VNode<any>': type, props, key (tsserver 2322)

To Reproduce

import { h, render } from 'preact'
import htm from 'htm'
const html = htm.bind(h);

/**
 * @template P
 * @typedef {import('preact').FunctionComponent<P>} FunctionComponent<P>
 */
/** @type {FunctionComponent<{}>} */
const App = () => {    // <-- tsserver gives the error on this line
  return html`<div />`
}

tsconfig.json

{
  "compilerOptions": {
    "module": "es6",
    "checkJs": true,
    "target": "ES6",
    "noEmit": true
  }
}

Expected behavior Obviously no tsserver error.

I think that FunctionComponent is expecting jsx components (which only ever return a single parent node; whereas HTM can return an array of VNode's).

reinhrst avatar Feb 12 '23 18:02 reinhrst

And just to be clear, I get the same behaviour using:

import { h, FunctionComponent, render } from 'preact'
import htm from 'htm'
const html = htm.bind(h);

/** @type {FunctionComponent<{}>} */
const App = () => {    // <-- tsserver gives the error on this line
  return html`<div />`
}

reinhrst avatar Feb 12 '23 18:02 reinhrst

As FunctionComponent generally shouldn't be used anyhow (lots of articles out there stating the issues it has), and htm being a somewhat niche option with fairly different semantics due to a lack of JSX, I don't think this should be supported. It'll only cause confusion for the majority who use JSX.

rschristian avatar Apr 19 '24 02:04 rschristian

@rschristian Can you link to articles describing why FunctionComponent should not be used (ideally with examples of what I should be using instead)?

As of today, the preact typescript documentation has examples with FunctionComponent.

I understand htm being used only by a minority, but it would be great if a simple "hello world" would be possible without giving a typescript error (possibly by adding something to the docs on how to do it correctly).

reinhrst avatar Apr 19 '24 07:04 reinhrst

Can you link to articles describing why FunctionComponent should not be used (ideally with examples of what I should be using instead)?

Check the "Why is React.FC not needed?" section here. It's an anti-pattern and has been for a few years now. Use type inference, there's absolutely no need to explicitly type components.

As of today, the preact typescript documentation has examples with FunctionComponent.

The TS docs on the Preact site are pretty out of date and rough unfortunately, and not a priority for me to fix at the moment. I wouldn't recommend you type events as it suggests either.

rschristian avatar Apr 19 '24 07:04 rschristian

Thanks, that makes sense!

Would you accept a PR for the typescript documentation page (I should have some time to update that in the next couple of weeks), or is this part of a larger operation to be doen later?

reinhrst avatar Apr 20 '24 09:04 reinhrst

PRs definitely welcome, as far as I am aware there are no plans for future content changes (beyond maybe https://github.com/preactjs/preact-www/issues/1098).

rschristian avatar Apr 20 '24 09:04 rschristian