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

Updated Typescript example and config files #1610

Closed
wants to merge 3 commits into from

Conversation

bestwestern
Copy link

@bestwestern bestwestern commented Apr 3, 2017

I added props and state to the example the way Typescript recommends
https://www.typescriptlang.org/docs/handbook/react-&-webpack.html

I updated tsconfig so the compiled code becomes what Zeit suggest at (e.g. async await)
https://zeit.co/blog/next

This way Typescript does it thing (intellisense, warnings at compiletime and removes declarations) and Zeit does the rest. (in the old example Typescript compiled to js and not jsx)

Advantages:

  • Removable - Typescript is just a layer.
  • Stackoverflow - you can post the JS code (which now looks good)
  • Issues - if you have an issue you need to post here on GH you would either have to post Typescript code or ugly JS code (compiled) Helpers could (rightly) say perhaps it is the Typescript to JS compilation that goes wrong.
  • Better use of Zeit servers capabilites. If they support async await why would we want Typescript to polyfill them. Therefore the goal should be to compile to es2017 and let Zeit do their thing.

The updates to the tsconfig are all necessary to achieve this.

@bestwestern bestwestern changed the title Updated example and config files Updated Typescript example and config files Apr 3, 2017
Copy link

@giladgray giladgray left a comment

Choose a reason for hiding this comment

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

links in PR description don't work.

"typescript": "^2.1.5"
"typescript": "2.2.1",
"react":"latest",
"react-dom":"latest"

Choose a reason for hiding this comment

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

latest react seems unsafe. i'd pick a version range just like above. how about ^15.4.0?

also space after the colon.

Copy link
Member

Choose a reason for hiding this comment

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

+1

Copy link
Author

Choose a reason for hiding this comment

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

thx

@@ -1,8 +1,8 @@
import * as React from 'react'

Choose a reason for hiding this comment

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

in my experience every TS file that uses JSX must have this exact line, because the JSX definitions are defined in the react types.

Copy link
Author

Choose a reason for hiding this comment

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

roger :)

<MyComponent />
</div>
<Link prefetch href='/pagewithasync'><a>Reactpage</a></Link>

Choose a reason for hiding this comment

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

are you really supposed to put an anchor tag inside a Link? seems like the Link is the anchor tag.

Copy link
Author

Choose a reason for hiding this comment

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

Changed to the way proposed in readme

}
constructor() {
super();
this.state = { clicked: false }

Choose a reason for hiding this comment

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

only set state in constructor if it relies on props. this should be a simple member.

public state: pageState = { clicked: false };

Copy link
Author

Choose a reason for hiding this comment

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

Thanks - I am learning from this :)

this.setState({ clicked: true })
}
render() {
return <div onClick={this.click.bind(this)}>

Choose a reason for hiding this comment

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

whoa no this is no good. do the bind on the function definition itself.

private click = () => { /* bound */ }

Copy link
Author

Choose a reason for hiding this comment

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

I started doing that, but didn't like the way it compiled - but I'll do it the right way again now. Thx

"jsx": "react",
"allowJs": true
"module": "es2015",
"target": "es2017",

Choose a reason for hiding this comment

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

why are you changing these two fields? this is a pretty significant shift in how the example works. what's wrong with commonjs es6?

Copy link
Author

Choose a reason for hiding this comment

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

See the pull request comment

"moduleResolution": "node",
"lib": [
"dom",
"es2017"

Choose a reason for hiding this comment

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

why is this needed? async/await are supported natively in ts 2.2

Copy link
Author

Choose a reason for hiding this comment

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

See update PR comment above

interface pageState {
clicked: boolean
}
export default class extends React.Component<pagesProps, pageState> {

Choose a reason for hiding this comment

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

i prefer whitespace between every block (blank line after every }). give your code some room to breathe man!

Copy link
Author

Choose a reason for hiding this comment

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

:) Now it's breathing

interface pagesProps {
stars: number
}
interface pageState {

Choose a reason for hiding this comment

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

interface names should use PascalCase just like classes. i prefer the I prefix convention too as it makes it obvious that this is a TS-only construct (and cannot be used in JS code): IPageProps, IPageState.

refer to any Blueprint component (perhaps this one) for tried-and-true conventions.

Copy link
Author

Choose a reason for hiding this comment

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

Thanks

Copy link

@OskarKlintrot OskarKlintrot left a comment

Choose a reason for hiding this comment

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

To use options in the config to be able to get a readable output to be able to post on SO makes absolutely no sense to me. It doesn't take longer to remove the TS syntax sugar than making the code postable (making the code more generic, remove irrelevant stuff, remove customer specific stuff etc). If you post the output then you might end up with code that works and can be readable but still makes no sense to a human in the way it's being written. And if you want to implement an answer you get you will have to do some reverse engineering and figure out how tsc transpiles the code and how you should implement it in TS to get the same output as the answer. This feels like one of those "It works, but..."-things.

@@ -0,0 +1,28 @@
import * as React from 'react'

Choose a reason for hiding this comment

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

Maybe consider camelCasing in the filename?

const res = await fetch('https://api.github.com/repos/zeit/next.js');
const data = await res.json();
return { stars: data.stargazers_count }
}

Choose a reason for hiding this comment

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

Maybe some space after these } as well @giladgray?

Copy link
Author

Choose a reason for hiding this comment

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

import` React from 'react'
import 'isomorphic-fetch'
export default class extends React.Component {
static async getInitialProps () {
const res = await fetch('https://api.company.com/user/123')
const data = await res.json()
return { username: data.profile.username }
}
}

From https://zeit.co/blog/next

Copy link

@giladgray giladgray Apr 4, 2017

Choose a reason for hiding this comment

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

yes please blank line after every function, class, member, etc.

a little tslint goes a long way.

@bestwestern
Copy link
Author

bestwestern commented Apr 4, 2017

I think the question is why would you want Typescript to compile it in the first place?
' The preserve mode will keep the JSX as part of the output to be further consumed by another transform step (e.g. Babel)' from https://www.typescriptlang.org/docs/handbook/jsx.html
Which is the case here.
Why rely on Typescript to do this? (It is not what they're "good at")
' If you post the output then you might end up with code that works and can be readable but still makes no sense to a human in the way it's being written. '
The compiled code is often exactly like the code Zeit uses in examples.

@OskarKlintrot
Copy link

I agree but three out of four of the Advantages listed in the PR is about posting code on SO and Issues and being able to actually use the output instead of the TS files.

@bestwestern
Copy link
Author

@OskarKlintrot isn't it 2/4?
But you do agree, so if I fix the other things (spaces and casing) you would back this pull request?

@OskarKlintrot
Copy link

OskarKlintrot commented Apr 4, 2017

To be honest, I appreciate the fix to get the example up and running but I don't really see the point of everything else (except maybe preserve). I still think what @giladgray wrote in the other PR should be the main focus of this example: "this seems like an ideal minimal typescript example: it provides a clean solution for the single problem of typescript compilation". But in the end I'm just a residue from the old PR and not part of Next.js.

Something that I personally think would contribute to the project is a "production ready"-example with proper setup of TS and handling of assets, the build in a separate folder (not the root), unit testing etc. Something to actually build upon to get something that can be delivered to a customer but still providing great DX. Basically having two examples:

  • examples/with-typescript-minimal-setup (the current example)
  • examples/with-typescript (a new example ready to build upon)

As I said I'm not part of Next.js and I'm currently using dotnet core for SSR and TS so don't take my words too serious, but... I think it can be a good idea to open up a new issue to either a) discuss rewriting the example (as you have done here) if you really really want that or b) discuss adding a new example (as I written above). See what the members and community of Next.js think and go from there. I understand that it must be frustrating to code stuff that just gets criticized and rejected so having a clear picture of what the project wants and needs is probably a good way forward. As I have written before, we discussed the current example for three weeks before everyone was satisfied and that's not a lot code and very unopinionated!

@OskarKlintrot
Copy link

Ping @giacomorebonato who wrote the current example.

@bestwestern
Copy link
Author

It is getting a bit frustrating when this (old setup)
image
keeps being preferred over this (PR):
image
When clearly the ladder is an ideal minimal typescript example.
The previous minimal setup actually did too much compiling, but was minimal in form of showing an actual typescript example.

@OskarKlintrot
Copy link

OskarKlintrot commented Apr 4, 2017

Yeah but that's like updating package.json and changing two lines in tsconfig.json. You have rewritten much more than that so the example in this PR is a different one than the current example. If you just would have fixed the bug and updated the tsconfig.json with good arguments (letting Next.js do the build is a good argument, being able to post the output on SO is not IMHO) I don't think anyone would see a reason why not to just merge it but that is not what you have done here. This PR is not about fixing something, this is about throwing out something that has three weeks of discussions behind it and replace it with something new. So I think a good approach from here is:

  1. Open a new issue about the bug in the current example (not running at all due to missing packages if I understand it correct) <-- Maybe a bit overkill since you already know how to fix it, some OS projects wants this anyway but not all, I don't know about Next.js
  2. Open a PR fixing that issue <-- This should be able to be merged without any discussions
  3. Open a PR about the minimal changes in tsconfig.json, don't change stuff like es2015 to es6, it's just polluting the history <-- I guess this would maybe end up in some questions about why if it's not backed by good enough arguments, I would definitely back this one if it looks good and only have the minimal changes to it
  4. Open a new issue about adding a more complete example, see if people want it and if they do, what they actually want
  5. When you have got a good picture about what the community wants from nr 4, open a new PR with that implemented (or work in progress so people can see that you are already on it)

Again, I'm not part of Next.js and don't talk for them. This is just a common way of contributing to OS projects.

@OskarKlintrot
Copy link

Keystonejs is an awesome project with some really solid guidelines for contributing that might be worth looking at. Their workflow is pretty much what I have described above.

@bestwestern
Copy link
Author

bestwestern commented Apr 4, 2017

'Yeah but that's like updating package.json and changing two lines in tsconfig.json.' +3
Every change in tsconfig is necessary and found trial and error :-/
That time could be saved by others trying to get Typescript setup.
It is actually the minimal changes to get the proper output (that is output like examples written by Zeit)
Thank you very much for the guide and feedback.
4+5 ok - but I would claim that I didn't make a more complete example - more like a minimal example (like they have in the other examples in the example folder)
Just a small example how it can be used and to show that it compiles to beautiful js

@OskarKlintrot
Copy link

I start to feel like I'm repeating myself but... I know that you haven't done a more complete example but you still have rewritten the example that we spent three weeks working on and that is where my problem is with this approach. I'm not complaining about necessary changes in tsconfig, I'm complaining about changes from es2015 to es6 (which was done in the previous PR). That means the same thing and is just polluting the history.

To sum up my thoughts on this:

  • Bug fixes are great
  • Leveraging Next.js instead of tsc is great
  • Unnecessary changing of options is not great
  • Rewriting an example with a lot of work behind is also not great unless discussed properly with the community and ultimately the members of the project
  • If you want to write something bigger than the current example code base-wise, feel free to open an issue for discussing it, I'm sure people will like the idea (at least I would love it)

Again, just MHO's.

@bestwestern
Copy link
Author

You and me both (about the repeating ;-) But I think we are on the same page (or close)
No es6 in this PR :) so zero 'unnecessary changing of options'
'Rewriting an example with a lot of work behind' That was literally 12 lines of code and no Typescript.
My example was filled with convention errors and I am grateful for the corrections.

I have some work now - I hope others will try my version and comment. I am learning from this :)

@OskarKlintrot
Copy link

Work was maybe the wrong word, discussion is what I meant but you get the point.

@giacomorebonato
Copy link

I like the "jsx": "react-native" settings, so .tsx compile to .js.
For the rest I like to compile TypeScript to ES6 so I can use latest language feature and then I don't mind to compile it again to ES5 with Babel.
But it is my humble and fast opinion. I will keep thinking about it.

@bestwestern
Copy link
Author

@giacomorebonato '..to ES6 so I can use latest language feature..' I think you can do that regardless.
My point is that we shouldn't make Typescript rewrite/polyfill features supported by next.js.
IMO typescript should just strip the code for declarations and the rest should be done by next.js
image
vs
image

Copy link

@giladgray giladgray left a comment

Choose a reason for hiding this comment

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

one of my favorite things about typescript is that it's basically babel + types (i never use babel in my typescript projects because tsc handles everything i could want out of the box, and then some). but Next itself provides support for a handful of ES6 concepts (namely async/await and JSX) so it kinda makes sense in this case to not handle those in tsc.

however, caring about the readability of the compiled output is the absolute wrong approach: typescript is a compiler, and you should trust it to produce functional code. you should not, however, expect to read or share that compiled code and it's unreasonable to hamstring your project for that goal.

const res = await fetch('https://api.github.com/repos/zeit/next.js');
const data = await res.json();
return { stars: data.stargazers_count }
}
Copy link

@giladgray giladgray Apr 4, 2017

Choose a reason for hiding this comment

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

yes please blank line after every function, class, member, etc.

a little tslint goes a long way.

@bestwestern
Copy link
Author

Some may (rightfully) care about lock in and bloating the code.

@OskarKlintrot
Copy link

@giacomorebonato Any thoughts on "preserve" vs "react-native"?

@giacomorebonato
Copy link

giacomorebonato commented Apr 5, 2017

If I target ES5 with TypeScript^2.2.2, I can't use even the Promise keyword. @bestwestern Do you confirm?

@OskarKlintrot "preserve" would be semantically more correct, but the problem when I made the PR was that it compiled to .jsx while next was looking only for .js files.

@OskarKlintrot
Copy link

Thanks for the explanation @giacomorebonato! 👍

@leesiongchan
Copy link

I am receiving a lot of `Cannot use JSX unless '--jsx' flag is enabled' and alias doesn't work with this configuration.

@giacomorebonato
Copy link

@leesiongchan are you writing JSX in .tsx files? The configuration should work then.

@timneutkens
Copy link
Member

I'm going to close this in favor of #2391

@timneutkens timneutkens closed this Jul 1, 2017
@lock lock bot locked as resolved and limited conversation to collaborators May 12, 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.

None yet

8 participants