Repository: TypeScript
Issue: Make jsx statement exactly equivalent to _jsx function call in "react-jsx" setting
Labels: Suggestion,In Discussion

# Suggestion

<!--
  Please fill in each section completely. Thank you!
-->

## 🔍 Search Terms

<!--
  💡 Did you know? TypeScript has over 2,000 open suggestions!
  🔎 Please search thoroughly before logging new feature requests as most common ideas already have a proposal in progress.
  The "Common Feature Requests" section of the FAQ lists many popular requests: https://github.com/Microsoft/TypeScript/wiki/FAQ#common-feature-requests

  Replace the text below:
-->

jsx, jsx-runtime, react-jsx

## ✅ Viability Checklist

<!--
   Suggestions that don't meet all these criteria are very, very unlikely to be accepted.
   We always recommend reviewing the TypeScript design goals before investing time writing
   a proposal for ideas outside the scope of the project.
-->
My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

<!-- A summary of what you'd like to see added or changed -->

In the `react-jsx` config setting (for the `jsx` field) statements like:
```
<Example key="hi" val={1} />
```
are transformed into:
```
_jsx(Example, { val: 1 }, "hi");
```
However, the _type_ of `<Example .../>` is hardcoded to be `JSX.Element`.

This suggestion is for the type to instead be the same as if `<Example .../>` was replaced by the `_jsx` call.

Alternatively, to add a `custom-jsx` config setting that would result in the above.

## 📃 Motivating Example

<!--
  If you were announcing this feature in a blog post, what's a short explanation that shows
  a developer why this feature improves the language?
-->

JSX is a format that has transcended its origins in React; however, the current typescript implementation only allows types that are nearly identical to React. This restriction is because JSX statements are typed independently of how they transpile. 

Experimental/Future UI libraries (or, any library that would benefit from in-syntax xml) cannot be safely typed unless their JSX statements all return the same type and their Components are all shaped the same as React. This limits the bounds of creativity (unless libraries are willing to lose type-safety).

## 💻 Use Cases

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->

I am developing a UI library where components function more like co-routines. They render children as they go, and then can return a value. Here is a mock-up example:

```ts
import { put, createSignal, Signal } from 'library';

function Page(props: {}) {
  // The return type of the Checkbox component is the result of the put(...) call
  const checked = put(<Checkbox key="check" label="Feeling Good?" />);

  put(<div>{checked() ? "That's great!" : "That's too bad..."}</div>);
}

function Checkbox(props: { label: string }): Signal<boolean> {
  const [value, setValue] = createSignal(false);

  put(
    <div>
      <input type="checkbox" id="example" name="example" />
      <label for="example">{props.label}</label>
    </div>
  );

  return value;
}
```

In the current system, the value of a JSX statement cannot be based on the passed-in Component.

I had also hoped to use generics in order to keep specific keys within the type system, which is useful for forms.

```ts
  // with generics reading the key parameters, the result type could be { str: string, checkmark: boolean }
  const result = put(
    <form>
      <input key="str" />
     <input type="checkbox" key="checkmark" />
   </form>
  );
```

Currently, the only workaround I see while maintaining type safety is to manually type the jsx statements without the transform. That is to do something like:
```ts
  const checked = put(jsx(Checkbox, { label: "Feeling Good?" }, "check"));
```

This of course works but is a more opaque developer experience.