Hacker News new | ask | show | jobs
by dcre 839 days ago
This is my favorite book about JS, and I always recommend it to people. It occurs to me for the first time that the lack of TypeScript might be a problem, because if I’m making recommendations to someone learning, I am definitely going to recommend they write TS instead of JS. On the other hand it may actually be helpful to learn the concepts in this book without the additional syntax overhead of type annotations, plus the more webby content doesn’t really have much to do with types anyway.
4 comments

I very much concur that it is better NOT to introduce TS when explaining JS fundamentals. I've seen smart engineers with a C++ background get tripped up on and very confused working with TS, because it's not clear to them what concepts are "language fundamentals" and what concepts are "the TS transpiler".

(Like expecting that just because you declared something as type X, that it guarantees at runtime it will always be type X, but it won't. You may get data from an API that _says_ it returns type X but the contents don't match. That can be valid code that compiles and has weird runtime behavior)

> I've seen smart engineers with a C++ background get tripped up on and very confused working with TS, because it's not clear to them what concepts are "language fundamentals" and what concepts are "the TS transpiler".

This is exactly why I never recommend TypeScript to new developers.

A similar problem (that used to be worse) with people learning JavaScript is the lack of separation between JavaScript and the DOM + browser APIs. 10+ years ago, people have told me how much they hated JavaScript and when probed about it further, would admit that it’s actually the DOM or new/inconsistent browser APIs that have caused issued.

JS has a number of its own flaws and quirks, yes, but there are two fundamental issues that make it harder to approach as a new learner (as opposed to, to say, Python) are how tightly coupled it has historically been to it’s primarily application case and how high or low level is this language?

What helped me understand the Runtime behaviour of TS is to understand that TS doesn't actually have strong typing. If it was named "LintScript", its name would be much closer to the truth.
This statement is quite questionable starting from the fact that there is no definition for what strong typing is.

Care to provide what you mean?

Strict TS won't compile pretty much any type-unsafe operation.

It's not perfect, the standard libraries are a bit too unsafe type wise, exceptions are untyped and need Either/Result-like data types to be handled but it's an extremely powerful language if you know it and it's ecosystem.

Most people though don't even bother reading the docs and can't tell you what a mapped type is or what is a disjointed union, etc.

If you are in a completely self-defined world, then yes you can trust the compiler. But I once built a react component which was called from library code and it simply did not adhere to the method signature (this was for a material UI table extension).

As soon as you have third party code calling your methods all bets are off. It could be JS calling your methods, or there simply is a hidden cast somewhere.

This is the moment that you realize that type annotations really are just a compile-time fiction, much like Python. At least in my definition, this is weak typing as the variable is physically capable of changing to any type at runtime, despite its type annotations.

TBF, this can also be true in C++, C#, probably most languages that can interoperate with other systems not written 100% in the same language + same runtime. After a while, you just get used to not trusting anything at the boundary - types are for your convenience and your internal logic, nothing more.
You are talking about something entirely different. Having weird interop is one thing. But having your internal state compromised because the language does not perform runtime checks is something entirely different.

In case of C++ this would lead to desastrous memory corruption. If all data is dynamic you can't have a safe program as data on the stack must be monomorphic or you corrupt nearby memory.

Naturally, you can defend against hostile input via excessive defensive programming (asserting against nulls, asserting against wrong types etc.). Or you simply use a strong static typed language.

Do you mean runtime type checking? Coming from compiled type safe languages, it was difficult to wrap my head around full type erasure too. Your name would have definitely helped.
> I've seen smart engineers with a C++ background get tripped up on and very confused working with TS,

The idea that someone is good at another language so they'll automatically be good at another is a common misconception. In fact, they're likely to be worse because they're less likely to spend time trying to learn things from the ground up and less likely to write idiomatic code.

It's especially bad with js/ts because of it's popularity (so lots of new programmers that complain about how NaN doesn't equal itself), and because it's the defacto web language so lots of people are forced to use it as a secondary language that don't want to spend time learning it.

NaN doesn’t equal itself in any language I’m aware of, fwiw.
I wholeheartedly agree. At most, I introduce JSDoc[1] to newer developers as standardising how parameters and whatnot are commented at least gets you better documentation and some safety without adding any TS knowledge overhead.

[1] https://jsdoc.app/

It is (or should be) common practice to parse/validate any external data you depend on. You should be doing this for Javascript too. I find that the library https://zod.dev/ is quite helpful for this
Agree. I wish tools like zod/valibot were first class in typescript.
Also effect schema if you're looking for something much more powerful and in effect-land.
> I am definitely going to recommend they write TS instead of JS

Why is that? If you want them to learn JS, teach/recommend them to learn JS?

Compile-to-JavaScript languages come and go, but JavaScript has remained. First learning vanilla JavaScript makes sense, and then add TS on top if you really have to. At the very least they'll be prepared for when TypeScript goes out of favor.

TypeScript isn't really a "compile-to-JavaScript" language in the same way that, say, Rescript is. Modulo a few corner cases (e.g. enums) which are now considered anti-features, TypeScript has the exact same runtime semantics as JavaScript - you can (almost) convert TypeScript to JavaScript just by stripping away the type annotations (and, if various ECMAScript proposals go through, you won't even need to do even that).

This is both a curse and the secret behind its success - it's arguably not a separate language, but instead an annotation layer on top of the existing language for encoding and checking your static reasoning and assumptions.

I guess by that same definition, Coffeescript isn't a compile-to-JavaScript language either, as it has the same semantics as vanilla JavaScript?

I think that's besides the point. My point was more that people who are supposed to learn JavaScript, should do so by learning vanilla JavaScript first, then they can move on to learning whatever is currently hyped by the zeitgeist (which happens to be TypeScript currently).

No, CoffeeScript doesn't have the same semantics as vanilla JavaScript; not in any meaningful sense I can think of, certainly not in the way that TypeScript does.

Most CoffeeScript will simply syntax error if you feed it into a JS interpreter (and vice versa), and there's no trivial syntactic transform to get around that (i.e. it's not just a new surface syntax over JavaScript). Various features in CoffeeScript have no equivalent in JS, so new code needs to be synthesized for them; even fundamental features that are shared by the two languages are different - for just one example, this [0] article shows that how a function is compiled in CoffeeScript is non-local - the compiler is tracking variable scopes to get around the fact that CoffeeScript and JavaScript have different scoping semantics.

With TypeScript, the "compilation" process is (almost):

  parse(typeScriptCode) -> treeMap(removeTypeAnnotation) -> write
That's it! TypeScript code is syntactically valid JavaScript code, just with added type annotations (and, as mentioned, soon that'll still count as syntactically valid JavaScript code); JavaScript code is syntactically valid TypeScript code without any type annotations - which doesn't make it syntactically invalid! Indeed, if you turn down the strictness settings on tsc to permit untyped code, the compiler doesn't even complain about it.

[0] https://donatstudios.com/CoffeeScript-Madness

CoffeeScript has quite a lot of code generation features, while TypeScript largely just removes code in order to transpile to JavaScript. The only exception I can think of is enums, and I suspect they wouldn't have put those in if they had it all to do over again.
Which further exposes the irony of casual hipsters who say things to me like "Thank God for Typescript, it's like a whole other language than JS". For example, a designer, who writes a quick one off plug-in for Figma in Typescript without realizing 99.9% could have been just written/pasted into the JS file (which is ultimately what Figma runs).
To be honest, in the appropriate context I will contradict myself and say that that you should think of TypeScript as a separate language. There's a lot of dynamic things you can do in JavaScript that will interact poorly with attempts to statically reason about your code with TypeScript; even if it's the approach you'd take in JS, when you add typing you should recalibrate how you approach the problem - that, to me, is an argument for thinking of it as separate language.

...but that's mostly just what I say to JavaScript devs, to be polite - to not tell them that their JavaScript code is bad, too. Code that's difficult to reason about statically is strictly worse, in my opinion, than code that's easier to reason about statically. And in that sense, TypeScript is just guiding you to write better JavaScript, which maybe undercuts its claim to being a language of its own.

Because TypeScript is the de facto standard way of writing JavaScript for most of the industry and it has killed all of the other compile-to-js languages.

The chances of it going out of favour are very slim, there's a giant ecosystem built on it and the language is very well loved by devs (should be second only to Rust).

Microsoft has 50 people on payroll working only on TS. Any competitor needs a gargantuan investment.

> Because TypeScript is the de facto standard way of writing JavaScript for most of the industry

It really isn't, but I guess that's really context specific. What country and sector are you talking about? For US-SaaS, what you're saying is probably true, but there is a whole world outside of that, and JavaScript is with 99% certainty much more wildly used than TypeScript.

> and it has killed all of the other compile-to-js languages.

Also it hasn't. I've been writing ClojureScript for the last 5 years, almost exclusively. And while the community is small, I wouldn't say it's "dead" or been killed. There are a bunch of compile-to-JS languages that haven't "been killed", besides ClojureScript.

But it serves basically the opposite niche compared to TypeScript.

> The chances of it going out of favour are very slim

Same has been said about everything, always, and it's always not true. Winds change, and surely so shall the winds of TypeScript. Not being able to see that it's possible, will put you at disadvantage.

Technically Haxe is still a thing, though its typical use case these days is almost 100% game development (including the JS target).
And JavaScript has a bigger ecosystem and more entrenchment, not to mention an international standard.
Not sure how's that relevant.

Any valid JavaScript is valid TypeScript and you're gonna write and read TS anyway in the industry.

They aren't in competition, but coming back to the first comment it sounds reasonable to start directly with TS for many users.

Your experience is not the industry. JS is widely used, almost certainly more than TS.
My experience may not, but the annual JS dev survey points that TS is the main way to write JS from years.
and not to mention terrible.
I use TS, I like it.

I'm not sure you're 100% right about it overtaking JS for most of the industry.

I wouldn't recommend it to beginners until they've learned JS because it's a lot of stuff to learn on top of JS to achieve basically the same outcomes (with fewer bugs). Chapter 5 in the Eloquent JavaScript book gets to higher order functions, which in TS means Generics. Nobody needs to learn Generics in Chapter 5 of their programming journey.

You also don't really appreciate how useful TS is until you've battled at least one project in plain JS.

(Arguably you can go a long way without HoF too, but perhaps not if you're hoping to understand other people's code.)

Flow has about a dozen of important features that typescript lacks (while being 10x smaller in terms of LoC).
Flow is basically a dead project outside of Facebook.

https://npmtrends.com/@babel/preset-flow-vs-flow-bin-vs-type...

Not that I think download metrics is the best metric to decide that, but even with that, flow-bin has almost half a million of downloads per day. That's far away from dead, at least in my world. And I'm guessing that doesn't count anything from Facebook as they most likely run their own registries.
flow-bin has substantially fewer downloads than coffeescript and both are declining. That is a dead project.

https://npmtrends.com/coffeescript-vs-flow-bin

I don't want them to "learn JS." Most likely the person in question is trying to write web applications, and I want them to learn what is most useful for that. After writing web applications for years without TypeScript and then for years with it, I cannot imagine going back. I can make complex refactors with very little worry. Thanks to type inference, most of the TypeScript code I write is indistinguishable from JavaScript, so the idea that learning TS takes away from learning JS is ridiculous. When I suggested that the extra syntax might be distracting at first, I meant for like... a week.
It's better if they learn the core language and then graduate to TypeScript (if at all, as there's active discussion of adding type annotations to the core language [1]).

An anecdote: I was sold a similar story on CoffeeScript back in the day, stressed myself out learning it, only to discard it a couple years later. TS won't have an identical fate as its shepherded by Microsoft, but eventually it will go the way of the dodo (whereas core JS will still be humming along).

[1] https://youtu.be/SdV9Xy0E4CM?feature=shared&t=380

This was the approach one of my first mentors recommended and it's served me well. Learn the core language and its features and then add tools/frameworks as needed. Lately it feels like we're teaching new devs popular frameworks and completely ignoring the fundamentals.
Yep. But business requirements dictate what happens and these frameworks are the fastest way to achieve business goals, which sucks as when the frameworks lose their appeal, those devs are gonna struggle to transfer their skills to something else.
It is useful to know vanilla JS. Right now I am learning an integration platform that uses JS for its scripting language, but you cannot use TS.
ts-node with ts can do script the same as node with js? surprised why TS can not be used as it's 'safer' for scripting.