Ask HN: Which TypeScript codebase should I study to get better?

158 points by nblavoie ↗ HN
I've been doing TypeScript professionally for the last 8 months or so and I would like to push further my knowledge of the language by reading well documented and high profile app or packages. Any suggestions ?

76 comments

[ 3.8 ms ] story [ 141 ms ] thread
I second this. Not only is the code well-written, the whole codebase is architected in a modular and layered way. Many things are well documented. You can probably step up your game and write a plugin for VSCode as an exercise.

The VSCode codebase is evidence TypeScript is built to scale further then Javascript.

Its editor component "Monaco" is the single reason that TypeScript exists. TypeScript was created in conjunction with (or for) this first project, of course the editor was first used in other parts of MS, and only later was also integrated into VSC.
Opening the VS Code inside VS code? I would feel watched, like my VS Code is wondering what the hell I'm doing.

Is it not good enough for me? Is it failing me in some awful way that I feel compelled to change it? Maybe it should get out of the IDE business if its not good enough? Maybe become a farmer, take a break from technology

Or you can think about it as looking under the hood of a car, or taking apart an iPhone to appreciate the beauty. But I do love the irony. I imagine people have run binary decompilers on the decompilers themselves before.
I remember the tale someone fuzzing the same fuzzer to find bugs. I can't find the link though.

General tools like an editor, a decompiler, or even an image editor can be used to modify the software itself. After all, if you're the creator of the tool itself, most likely you feel comfortable using it.

What I always wonder is how people built the first tools. How did people compile the first version of GCC? How did people build the first programming language? How did people built the first OS? I can imagine ways to solve these, but I guess the tale behind how they did it is what makes me wonder.

I learnt a lot from looking at the code code base when it was first released (and back when TS didn't have so much material available).
How does one approach looking at a (large) codebase with intent to learn? Where do you begin?
Read "Working Effectively with Legacy Code"

    if (!!process.send
Is there something I'm missing here? Why not just:

    if (process.send
`!!x` is guaranteed to evaluate to a boolean value of `true` or `false`.

`if (x)` evaluates truthiness of `x` which in Javascript land might behave differently. I don't know how off the top of my head, but I know it's something to be cautious of in this language and its derivatives.

An if statement works exactly the same whether you pass it a boolean true or false, or any truthy or falsy expression.

In other words, these are 100% equivalent:

  if( anything ) { ... }

  if( !!( anything ) ) { ... }
The !! is redundant here, unless there's something relevant that isn't shown in the if statement excerpt in legohead's comment.
It's just explicit coercion.

If there was a linter rule I could turn on to require booleans in if-conditions, I'd enable it.

`!!` might seem silly, but it's a hint that you intended for coercion to happen. A similar but better example would be preferring `if (x > 0)` over `if (x)` even though non-zero is truthy.

There's an even better case for returning `!!x` from a function even though you could return `x` and let the call-site coerce it. The problem with that is that the call-site can build a dependency on the value of `x` beyond truthy vs falsey.

In a weakly typed language like Javascript, I don't think you'll ever regret being a little more explicit.

I much prefer the more explicit `Boolean(anything)` for this reason.
> `!!` might seem silly, but it's a hint that you intended for coercion to happen.

"Silly" is in the eye of the beholder, of course. But it is definitely redundant. Using a value in an if statement is not just a hint, but an explicit guarantee that all you are doing with the value is testing it for truthiness. !! adds no information or insight that isn't already there.

> A similar but better example would be preferring `if (x > 0)` over `if (x)` even though non-zero is truthy.

Obviously you know this, but if( x > 0 ) is not the same thing as if( x ). You can't substitute one for the other: a truthiness test on x is different from testing the numeric value of x for being greater than zero. If x is -1, the two statements will do different things.

> There's an even better case for returning `!!x` from a function even though you could return `x` and let the call-site coerce it. The problem with that is that the call-site can build a dependency on the value of `x` beyond truthy vs falsey.

That's a completely different situation. When you return a value from a function, there is no guaranteed truthiness test as there is with an if statement. You're just returning a value "as is".

So for example, if you have a function that creates some private object and it's defined to return a truthy or falsy value to tell you if the object was created, it could be tempting to say "I have a variable with a reference to the object I'm creating or null if it failed. I can just return that variable!"

As you mentioned, the caller could hold a reference to that return value, thus holding a reference to the object that isn't necessary - and could lead to a memory leak. By using "return !! myObject;" instead, you avoid passing the object itself back to the caller and just give them a true/false value instead. This is a good thing to do.

But an if statement is not the same thing. The if statement already has a guarantee that all it will do with the value is test it for truthiness and not keep any reference to it. Adding !! doesn't convey any information to the reader that isn't already there.

I like being explicit too, but I don't like adding extra verbiage to something that is already completely explicit.

> In a weakly typed language like Javascript, I don't think you'll ever regret being a little more explicit.

"!!" is not needed in the shown case. It might be needed if you want to pass somewhere or return "boolean" value, but in the example it's only the "if" thing.

I think you're right. It looks like an oversight.
The TypeScript compiler itself is written in TypeScript: https://github.com/Microsoft/TypeScript
That's cool but surely any implementation of a language in itself is going to deal with some pretty fringe situations, so it might not be the best thing to read in order to learn how you should write other things in that language?
Exactly what I was thinking while browsing the code. In particular, I'm looking for the "right way" to code the application. Using Observable, Promise, patterns, etc. To get to the point that I don't ask myself all the time if it's the right way to do the things.
A caution: I’ve observed a lot of code that’s been damaged by enthusiastic use of patterns or library features, and I’ve met novice programmers who doubt whether their code is good code based solely on the fact that it doesn’t use Observable, Promise, patterns, etc.

Look for code that is correct, clear, concise, testable, etc.

There's no reason why implementing a language in itself would be special, it's not dealing with fringe situations in any sense of the word. It is traditional to write compilers in the very language they compile, except for slow interpreted languages, and a compiler is a very well-studied type of program that includes a variety of different types of code such as straight text processing, error reporting, and recursive data structures. Compilers are often used as test beds for new language features, famously, Niklaus Wirth would measure language improvements based on how much they would improve the language's compiler.

Think about it this way: a TypeScript compiler takes a bunch of text as input, and produces a bunch of text as output. That's not really special or weird, is it?

(The only hard part is the “bootstrapping problem” which is what happens when you want to write a compiler for language X using language X, but you can’t compile it because you don’t have a compiler yet.)

a TypeScript compiler takes a bunch of text as input, and produces a bunch of text as output. That's not really special or weird, is it?

In the case of a compiler used for production, it may have lots of optimizations, most of the time, this optimizations are non-idiomatic code that's hard to understand and its purpose its not obvious.

Can you give an example of this? Most of the compilers I've seen have excellent code bases, with good separation between the different components, probably because compilers are so well-studied. It can be surprising what the most productive part of the compiler is to optimize. Often the lexer is heavily optimized due to its outsized impact on performance, but even then, the code looks idiomatic to me.

- Scanner.Scan() https://github.com/golang/go/blob/master/src/go/scanner/scan...

- scan() https://github.com/Microsoft/TypeScript/blob/master/src/comp...

- Lexer::LexTokenInternal() https://github.com/llvm-mirror/clang/blob/master/lib/Lex/Lex...

All three examples are heavily optimized and hand-written but they’re still clear and easy to follow.

Interested in that bootstrapping process. Is it just that the first version has to be compiled with some other language. From then on, you just use the previous version that you have compiled already?
Yes, that is normal. If you can imagine, this process dates back to the first assemblers, which were written in assembly and then converted by hand to machine code.
From what I recall, start by writing a minimal compiler for language X in some other language, Y, and compile it. Now you have an X-compiler written in Y.

Rewrite the minimal compiler in X, and compile it using the one that was written in Y. That gives you an X-compiler written in X compiled from one written in Y.

To be sure _that one_ works, recompile your X source code with that last compiler. Now you have a compiler written in X and built with one also written in X.

Continue to add more features written in minimal-X to get X-compilers with more X features.

Just as small improvement, for the first step an interpreter is a better approach, just to ease the bootstraping process by not having to write a compiler backend twice.
And what about the "TypeScript Design Patterns" book, you guys have read it ? Is it good ? Is it worth the investment ? http://amzn.to/2ym40AW And what about Online Courses on Udemy?
I recently wrote and submitted a pull-request to DefinitelyTyped. Find non-Typescript packages and add the typings :).
Or, if you're a hero, find the packages with bad typings and fix them <3333
My favorite is finding the libraries that now have typings (they migrated to TS themselves or got a good definition PR they accepted, maybe even a PR you sent the library directly), and sending the removal PR to DT. DT is huge so every file that can be removed is a little bit less of a papercut in checkout time and testing time for the next branch/developer.
and please break the codebase of people using these types by not following semver (keeps happening to me with typings -_- should really start using a lock file)
We use TypeScript heavily at Ionic.

Ionic Framework 2+ is TS: https://github.com/ionic-team/ionic

Our new web component compiler Stencil is also TS: https://github.com/ionic-team/stencil

Nice. Simple question. How do you educate your developers on TypeScript or Angular? What is the training path they follow to become top notch?
No specific education, just jump in and follow existing patterns. Most devs we hire pick it up quickly and we have people here that can help with more complicated questions. We have a few people who really grok the type system and can help with nasty type issues when they come up.
I really love this ORM project for typescript:

http://typeorm.io/

It's also one of the larger enterprise grade projects that i've seen done natively in TS. It pretty much uses all the bells and whistles that the language provides. Some decent patterns, and an active developer community.

A little off topic, but is anyone using this in a large production environment? I'm currently using sequelize for a side project and haven't been terribly happy with it. TypeORM looks better but it feels like it has just sprung out of nowhere and is maybe too new to use in the real world.
Project I know just replaced sequelize with TypeORM and is about to go into production - the beta has been great

There is this issue talking about production readiness with more feedback:

https://github.com/typeorm/typeorm/issues/591

You should know about quirks like this one:

http://typeorm.io/#/relations-faq/avoid-relation-property-in...

I've been spending more and more time reading the code and tracking the open issues - getting comfortable with phasing it into a production system

Three i've read through recently:

1. InversifyJS - DI in Typescript / JS

https://github.com/inversify/InversifyJS

2. TypeORM - as it says, might be the best ORM for nodejs projects:

https://github.com/typeorm/typeorm

3. Searchkit - ES web frontend - react + typescript

https://github.com/searchkit/searchkit

+1 for InversifyJS - I learned a lot of TypeScript by just reading through the actual Inversify codebase, and then used what I learned to write what would become https://github.com/inversify/inversify-express-utils.

Also, thanks to the Inversify contributors for continuing to maintain and improve express-utils!

funny i'd just bookmarked inversify-express-utils the other day and have been meaning to go back to it :)

the Typescript ecosystem has really come a long way

+1 for InversifyJS from me too. I've also been looking at the inversify express utils lately -- loving it so far!

Do you know if there are any plans for allowing the http context (req, namely) to be injected into services? Similar to the IHttpContextAccessor in dotnet core?

I have some use cases for using pieces of the http context (headers) to instantiate some transient services. I started putting together my own pieces to see what I could get away with. Looks like it works okay, but I had to create a new container per request, using the `Container.parent` to link them.

The TypeScript compiler is the canonical corpus of code written by TypeScript experts, and I learned a lot of interesting style from the time I've spent with it. (Fun fact: they don't use 'class' in the compiler at all, but instead have a different pattern for passing around interfaces+state that is much more TypeScript-y.)
Fun fact: they don't use 'class' in the compiler at all

Looks like a class to me: https://github.com/Microsoft/TypeScript/blob/master/src/comp...

What strikes me first is the comment above the function :

// Keep the class inside a function so it doesn't get compiled if it's not used.

I didn't know it was possible.

(comment deleted)
We do use classes in the test harness, services layer, and to polyfill es6 Map. We just don't use them in the design of any compiler subsystems.
This is very interesting to me.

Is the reasoning behind this documented anywhere?

I could only find instructions the coding guideline indicating as much (here: https://github.com/Microsoft/TypeScript/wiki/Coding-guidelin...) but couldn't find why. I'd love to know why, may better inform my usage of typescript.

bring a horse to water ... but cant make it drink

you have all the answers in front of you do you need them to read the code for you? Come on man. A little effort please. Its not like you have been neglected with info.

For better or worse? I've avoided classes in our codebase because I don't like the lack of privates via closure (revealing module pattern) and it's transpiler overhead, but it's a very powerful organization tool. I've found code to be much neater in the class format.
Looks like C++ circa 2008. Careful with those abstractions. That seems a stone's throw away from template metaprogramming.
Could you cite an example of the interfaces+state pattern? You've piqued my interest.
does anyone have some recommendation on how to debug typescript compiler, it seems like console does not work there, I am trying to just step through tsc.ts, but gulp local always complains that console is not defined. Is there any alternative in stepping through the compiler?
If you want to learn more about 3d engines (game or rendering), I would recommend BabylonJS: https://github.com/BabylonJS/Babylon.js

It has fairly good docs: http://doc.babylonjs.com/ as well as an active forum for developers and users: http://www.html5gamedevs.com/forum/16-babylonjs/

Other options mentioned are also good - the Typescript compiler (https://github.com/Microsoft/TypeScript) is good to get started with especially if you read this Gitbook: https://basarat.gitbooks.io/typescript/content/docs/compiler...

You could also search popular typescript github projects that are more closely related to what you work on, but the Typescript compiler and Babylonjs 3d engine are both well written projects with fairly good documentation in my opinion.

(comment deleted)
This is a great discussion! Reading good code is the best way to learn.

Reading the NativeScript code gave me a really good impression of TypeScript, although I'm just learning it and haven't written much yet myself.

https://www.nativescript.org/using-typescript-with-nativescr...

I have a huge blob of old JavaScript cellular automata code I want to rewrite in TypeScript, but first I want to read some good TypeScript code before starting so I don't mess it up.

It has a bunch of old "frameworky" meta-programming code and data structures that I've painted myself into a corner with (see the "type definitions" comments), which I'd like to throw away and re-implement from scratch, because TypeScript is much better suited for that kind of stuff. And then there's a bunch of brute force bit bashing and number crunching code that I hope will just run without any modification and only a little repackaging, which is another nice benefit of TypeScript.

https://github.com/SimHacker/CAM6/blob/master/javascript/CAM...

Depends. How good are you at JS? Because I think learning what great JS looks like will give you a better grounding in what TS is actually adding to JS and what is “good TS” vs “good general practice”.

That might sound dismissive of TS but it’s not, I’m just trying to get a sense on what you’re trying to learn from TS.

If you're going to be doing React - the Blueprint source (Palantir's react ui kit) seems to be really well written. I don't work there... I just use it.

https://github.com/palantir/blueprint/tree/master/packages/c...

Few questions:

1. How has been your experience with Blueprint JS?

2. Is it possible to take a look at your work?

3. Would you recommend using it? If yes, what types of apps?

I use it for internal admin type apps. Can't really show to it you though sorry.

It is pretty damn thorough tho and the css is relatively minimal if you need to custom skin the components.

Yes I would recommend it highly. Just look through the components they have mostly everything covered.