Skip to content
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

JSX Support #2673

Closed
wants to merge 8 commits into from
Closed

JSX Support #2673

wants to merge 8 commits into from

Conversation

fdecampredon
Copy link

Following the discussion in #296, here is a PR that adds support for JSX constructs.

And some details about the implementation/spec :

  • JSX elements are only parsed if a triple slash directive is present :
///<jsx factory="myFactory" />
  • JSX elements are type checked as a call of the factory function :
///<jsx factory="myFactory" />
<MyComp attr={something}> Something </MyComp>;
// typechecked as : 
myFactory(MyComp, { attr: something}, " Something ");
  • JSX elements are emitted unchanged (only formatted).
  • To reproduce React's behavior, depending of the case of the tag, the first argument of the function call might be treated as a string:
///<jsx factory="myFactory" />
<div />
// typechecked as : 
myFactory("div", {});

<MyComp />
// typechecked as : 
myFactory(MyComp, {});
  • JSX directive factory attribute value might contain any property access level:
///<jsx factory="myNameSpace.myNameSpace1.myFunc" />
///<jsx factory="React.createElement" />
  • In General JSX elements describe how a component should be instantiated (at least in React). In this context the way of how attributes should be checked is generally dictated by the tag.
    For this purpose, types for JSXElement call are only inferred from the first argument (the tag).
///<jsx factory="test" />

declare function test<P>(p1: P, p2: P): void;

var Comp = { items: "foo" };
test(Comp, {}); // no error P is inferred as `{}` 
<Comp />; // error Argument of type '{}' is not assignable to parameter of type '{ items: string; }'.

The service integration is minimal and ported from my old version of jsx-typescript, so not well tested.

@msftclas
Copy link

msftclas commented Apr 8, 2015

Hi @fdecampredon, I'm your friendly neighborhood Microsoft Pull Request Bot (You can call me MSBOT). Thanks for your contribution!

In order for us to evaluate and accept your PR, we ask that you sign a contribution license agreement. It's all electronic and will take just minutes. I promise there's no faxing. https://cla.microsoft.com.

TTYL, MSBOT;

@msftclas
Copy link

msftclas commented Apr 8, 2015

@fdecampredon, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR.

Thanks, MSBOT;

@paulvanbrenk
Copy link
Contributor

Thanks for the PR, I'll take a look later tomorrow.

@jbondc
Copy link
Contributor

jbondc commented Apr 9, 2015

@fdecampredon Great stuff

I'm not sure how, but it would be nice to see this solved as general template string:

///<template name="jsx" compile="myFactory" />
jsx`<div />`
// typechecked as : 
myFactory("div", {});

@@ -316,6 +316,20 @@ module ts {
return visitNode(cbNode, (<ExternalModuleReference>node).expression);
case SyntaxKind.MissingDeclaration:
return visitNodes(cbNodes, node.decorators);
case SyntaxKind.JSXElement:
return visitNode(cbNode, (<JSXElement>node).openingElement) || visitNodes(cbNodes, (<JSXElement>node).children) || visitNode(cbNode, (<JSXElement>node).closingElement);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrap these to keep things consistent with the rest of this function.

@CyrusNajmabadi
Copy link
Contributor

I'm concerned about the incremental parsing issues here. If you have:

var v = <book>x;
var y;
var z;

And you add something at the end like </book>, then we won't know to go reparse that original statement.

We'll need to track (in the parse tree) where type assertions are used. And then, during incremental parsing, we'll have to walk into anything that has a type assertion, and see if that type assertion could match a close tag that follows it in the file. If so, we'll have to consider the node ineligible for incremental reuse.

@fdecampredon
Copy link
Author

@CyrusNajmabadi
Do you want that I try to address the Incremental parsing issue in this PR, or do it later in a separate PR if that one is merged ?

@paulvanbrenk
Copy link
Contributor

The typechecking using the factory seems problematic as a general solution, and there is no clean consensus at this point what the right direction is... can you remove the type-checking from the PR and for now type things as 'any'.

I'm aware of the limitations, and agree we should do something else in the future. Just not sure what...

@fdecampredon
Copy link
Author

any or {} ? because that was the 2 options described by @mhegazy here #296 (comment).
And any seems to have big impact of what could be done in the future.

@paulvanbrenk
Copy link
Contributor

any or {} which ever is easier for you to implement.

We should come up with a design for typing things before we actually release this and make changes based on that. But we should focus on a solid (and performant) parsing story first. First walk, then run etc...

Thanks for all the work!

@CyrusNajmabadi
Copy link
Contributor

@fdecampredon

Do you want that I try to address the Incremental parsing issue in this PR, or do it later in a separate PR if that one is merged ?

I would definitely want the incremental parsing issue resolved before merging. Otherwise, we could end up in a state where you're editing, but invalid parse trees. We want to avoid that like the plague, else we will have many hard to track down bugs.

Here would be my preferred order of work:

  1. Get parsing fully complete. Have system report that JSX elements are not supported during typecheck, treat them as 'any' in the typesystem, and skip processing them further. Ignore JSX elements for emit.
  2. Get emit working. I would hope this would be a fairly simple task.
  3. Come to consensus with how this should be properly represented in the Type-system (will likely require language design approval), then do the type checking side.

This allows the work to be spread into much smaller pieces, and allows us to make sure that things are working properly before going on to the next stages.

Thanks!

@chicoxyzzy
Copy link
Contributor

also notice that some tags should omit their close tag

@duanyao
Copy link

duanyao commented Apr 18, 2015

How about using double angle brackets for XML-like syntax in typescript? This should avoids conflict with type assertion:

<<div id=1>>
  var text = (<Element>document.querySelector("#foo")).textContent;
  ...
<</div>>

I think even if the TS compiler/IDEs are smart enough to recognize single-angle-bracket XML tags, it is harder for human eyes to quickly distinguish single-angle-bracket XML tags and type assertions and generics.

@basarat
Copy link
Contributor

basarat commented Apr 18, 2015

How about using double angle brackets for XML-like syntax in typescript

Too verbose. There have been other simpler recommendations like <?div> where only the first instance needs changing.

That said I strongly prefer what @fdecampredon has done and it would be awesome to have in TS core.

@duanyao
Copy link

duanyao commented Apr 18, 2015

@basarat Yes double angle bracket is verbose, but personally I think it is more pretty-looking than something like <?div>. Besides, single angle brackets are already used for type assertion, generics, and comparisons in TS, and double angle bracket makes it easier to recognize XML tags by human eyes. We usually read codes more times than write them, so readability of the syntax is more important than writability, I think.

P.S., smart code editors may autocomplete double angle brackets, e.g., after you type <div>, editors can generate <<div>><</div>>, so the verbosity may be not a big problem.

@basarat
Copy link
Contributor

basarat commented Apr 18, 2015

Did you imagine every level or just first level?

<<div>>
    <<div>>
    <</div>>
<</div>>

@duanyao
Copy link

duanyao commented Apr 18, 2015

Probably every level, because TS codes may be mixed inside XML elements.

@BohdanTkachenko
Copy link

Any chances that TypeScript will get official support and this PR will be merged? I want to migrate my project to TypeScript, but JSX support is essential for me.

@mhegazy
Copy link
Contributor

mhegazy commented May 1, 2015

last time I chatted with @fdecampredon he was busy moving, So hopefully we can get in soon :)

@icetraxx
Copy link

icetraxx commented May 1, 2015

+1 on getting this in soon.

@DAddYE
Copy link

DAddYE commented May 4, 2015

I would consider Typescript as well for my next project if it can support JSX. So please asap! 👍

@paulvanbrenk
Copy link
Contributor

I want to set some expectations here. We won't be able to get this in the 1.5 release, however we're moving as fast as we can.

@tinganho
Copy link
Contributor

tinganho commented May 5, 2015

@fdecampredon could you please look at #3022 ? I would like to have your thoughts on it. I know that you commented before that you didn't expect the TS team to include JSX and thus created your own fork because you thought it "was the right way", seems like they changed their mind now.

@icetraxx
Copy link

icetraxx commented May 6, 2015

@fdecampredon @CyrusNajmabadi How about using .jsx.ts instead of .tsx for the file extension? This is more consistent with what TypeScript already does with d.ts files (as proposed by @jonathandturner here #3022 (comment)) and doesn't add an entirely new file extension.

@fdecampredon
Copy link
Author

@CyrusNajmabadi @paulvanbrenk would you mind if I completely rewrite the git history, it's a bit a mess now and a lot of things has been added then removed (especially in scanner).

@koistya
Copy link

koistya commented May 7, 2015

Would be nice if it could also work with .react.ts as well as the default .ts file extensions.

@DAddYE
Copy link

DAddYE commented May 7, 2015

I'll rather prefer .tsx or jsx.ts

Sent from my iPhone

On May 7, 2015, at 4:56 AM, Konstantin Tarkus notifications@github.com
wrote:

Would be nice if it could also work with .react.ts as well as the default
.ts file extensions.


Reply to this email directly or view it on GitHub
#2673 (comment).

@Lenne231
Copy link

Lenne231 commented May 8, 2015

Is there a good reason to have a special file extension? I don't think so, if it's part of TypeScript it should be allowed to use JSX in every *.ts file. JSX uses *.jsx to differentiate from *.js but TypeScript is allready differentiated from *.js by using *.ts, so there is no need for a special file extension...

@majodev
Copy link

majodev commented May 13, 2015

Really looking forward for this!

@CyrusNajmabadi
Copy link
Contributor

I'm ok with you rewriting things. @paulvanbrenk are you ok with this?

@paulvanbrenk
Copy link
Contributor

Go right ahead.

@fdecampredon
Copy link
Author

@paulvanbrenk @CyrusNajmabadi I tried to address all your feedbacks except for incremental parsing.
However from what I read in #3203 things have changed.
What do you want that I do ?
Should I wait for the as operator to be merged and remove everything that try to disambiguate JSX from type assertion ? Or simply finish it like that ?
@CyrusNajmabadi do you want to explain me or in details what should be done for incremental parsing, or implement it yourself ?

@CyrusNajmabadi
Copy link
Contributor

Hi @fdecampredon . I would wait on 'as' to get merged in, and i would remove all the disambiguation logic you have. With TSX, we'll be requiring that you use 'as' for type assertions, and things like <blah> will always be xml tags.

This does mean that .ts code can't simply be dropped into a .tsx file, but c'est la vie.

Because of these changes, i don't believe there is any work you will need to do for incremental parsing anymore. The problem with incremental parsing was the ambiguity with <tags>. Basically, we would have had to have logic that would say "after an edit, we need to know if we need to reinpterpret any preceding type-assertions as xml-tags". Now, because there is no ambiguity, we don't have to do this work.

So yaay, everything gets simpler.

@RyanCavanaugh
Copy link
Member

This work has been folded in to a future PR

@microsoft microsoft locked and limited conversation to collaborators Jun 18, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.