Skip to content

JSX elements should not rely on only global JSX.Element type #4195

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

Closed
tinganho opened this issue Aug 6, 2015 · 4 comments
Closed

JSX elements should not rely on only global JSX.Element type #4195

tinganho opened this issue Aug 6, 2015 · 4 comments
Labels
Discussion Issues which may not have code impact

Comments

@tinganho
Copy link
Contributor

tinganho commented Aug 6, 2015

I find this to be very limiting:

export namespace JSX {
    export interface Element {

    }

    export interface IntrinsicElements {
        div: {};
    }
}

let a = <div></div>;
tsc test.tsx --jsx react --noImplicitAny
test.tsx(2,18): error TS1148: Cannot compile modules unless the '--module' flag is provided.
test.tsx(12,9): error TS2602: JSX element implicitly has type 'any' because the global type 'JSX.Element' does not exist.
test.tsx(12,9): error TS7026: JSX element implicitly has type 'any' because no interface 'JSX.IntrinsicElements' exists
test.tsx(12,10): error TS2304: Cannot find name 'React'.

It doesn't complain if I remove the export keyword. Why does it need to rely on a global type? Can't it not be local? I want to develop a JSX framework and I want to create a local type of JSX.Element etc. and then compile the definition file. I did began with declaring JSX.Element in a d.ts file, but there was some limitation with that approach. Also all my modules is of external type.

@RyanCavanaugh
Copy link
Member

I don't see any value in a JSX expression meaning one thing in one place and one thing in another. It's similar to Array -- string[] is just a shorthand for Array<string>, and [] is a syntax of the global type Array. We don't perform a local lookup for that name.

@tinganho
Copy link
Contributor Author

tinganho commented Aug 6, 2015

Ok I think I can agree on that.

@tinganho tinganho closed this as completed Aug 6, 2015
@RyanCavanaugh RyanCavanaugh added the Discussion Issues which may not have code impact label Aug 6, 2015
@jchv
Copy link

jchv commented Sep 4, 2016

Okay, so I'm relatively new to TypeScript and just trying to figure stuff out. Does this kind-of incidentally imply that React or another JSX-utilizing library can't be loaded through the module system, and instead must be global? I say this because that's what seems to be the case. If I define the JSX interface manually somewhere else, I can't tie it back to the local definition of React, for example.

If this is the intended behavior, then it is somewhat inconsistent, because React.createElement can be local and work fine, but JSX.IntrinsicElements cannot. The side-effect is that in fact, the meaning of a JSX element is truly affected by local scope. Maybe that's not ideal, but it's clearly true today. And to me it seems there is not a logical workaround except to reverse this decision and make it a local lookup.

@morrisallison
Copy link

JSX is just sugar for plain JavaScript calls. Nothing about it is global, and its types shouldn't be either.

Given the docs, I was under the impression that "JSX type" would be determined by a local lookup of what was set by the jsxFactory option.

I don't see any value in a JSX expression meaning one thing in one place and one thing in another.
@RyanCavanaugh

Nowadays there's plenty of compatible JSX libraries, so there's clearly as case for being able to write components that're compatible with different libraries. TypeScript is great for ensuring compatibly with multiple libraries. However, TypeScript makes this difficult, because the JSX type is global.

The following code is valid, but fails type checks.

import * as assert from 'assert';

import { h } from 'preact';
import * as render from 'preact-render-to-string';
import * as React from 'react';
import * as ReactDomServer from 'react-dom/server';

type JsxHandler<Output> = (node: any, props?: any, ...children: any[]) => Output;

const props = { hello: 'Hello World' };

function makeComponent<T>(h: JsxHandler<T>) {
  return (props: any) => <div>{props.hello}</div>;
}

const PreactComponent = makeComponent(h);
const ReactComponent = makeComponent(React.createElement);

assert.equal(
  render(PreactComponent(props)),
  ReactDomServer.renderToStaticMarkup(ReactComponent(props))
);

@microsoft microsoft locked and limited conversation to collaborators Jun 19, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Discussion Issues which may not have code impact
Projects
None yet
Development

No branches or pull requests

4 participants