I love this thread, it has two of my favorite HN topics:
1) People shitting on JavaScript not realizing that their "obviously better" solution was considered and found not a good solution.
2) People shitting on TypeScript not realizing that conditional types and template literal types are awesome. I really like those type-safe routers (https://tanstack.com/router/v1/docs/guide/type-safety) and fully-typed database clients (https://www.edgedb.com/docs/clients/js/index#the-query-build...).
I really dislike how unpredictable the typescript compiler can be. What I mean is, there isn’t a simple set of rules I can understand to know when annotations will be required. Most of the time, this doesn’t matter, but occasionally it blows up and development comes to a screeching halt. Contrast this to, say, Java and ML type-systems, which are highly predictable.
On the other hand, Stockholm Syndrome is an underrated and under-researched effect in software engineering.
There are people ready to defend with their life the most obtuse, inane piece of technology, just because they have invested a non-negligible amount of time getting used to its quirks, that they become completely blind to its faults, and start to believe those very quirks are actually positive and to be cherished.
> TanStack Router is built to be extremely type-safe.
This is alludes to my only major complaint about typescript. IMO, something is either type-safe or it ain't. I don't like how the JS bleeds through if you aren't careful.
I'm not a TS hater by any means, I use it regularly and am usually pleased. I just can't help but compare it to the [S,Oca]ML compilers I'm so fond of.
There is so much wrong with JS, the only reason it is used is because people are literally forced to.
It took a long time for js devs to accept the notion of a compiler with TS. While TS is an improvement, it’s only a localized one. No chance ever, any other language could have replaced it.
Have you used EdgeDB in prod? I’m itching to try it, but am too worried about general instability. Seems like too many moving parts. Love the DX though, it’s really clean and well thought out.
From the comments here, I was expecting to find myself hopelessly out of date, and to end up with a migraine trying to parse through a mindnumbing list of changes. Turned out I was mistaken.
> Me: oh, cool, they fixed so many tiny things I had bumped up against
> Some others: oh no, why are things changing
I'm not getting it. Maybe I'm reading this wrong, but to me these seem pretty obvious small issues to smooth over.
hmm... I've been using JS/TS for almost as long as they've existed. A lot of these are nice. Some less so. Some quick thoughts:
- Tagged template strings. This just feels dirty to me. Probably won't use, but when I see it in a code base I won't be so confused at least
- matchAll. I've never needed this. I've used match with g a bunch, but I never need the capture group.
- Promise.allSettled. THIS is useful. I've implemented this (under a different name) in almost every code base I've worked on, and got bit HARD by not understanding this behavior long ago (huge production outage that took hours and many engineers to discover)
- globalThis. EW. Don't think I have to elaborate
- replaceAll. It's always annoyed me needing to use RegEx for simple replace all. so Yay!
- ??=, &&=, ||= These seem really useful, but also potentially hard to read, but I think if I get used to their existence they'd become second nature
- # private... not sure why they didn't just use the "private" keyword, but I don't care. I almost always use TypeScript anyways
- static ... YAY! finally. Again, if they could do this i don't see why not "private"
For the TypeScript stuff I'll just say the type system has kinda jumped the shark, but I don't hate it. It's SO robust and of all the new stuff being added I'll maybe use 1/10 of it, but it's good to know I can describe literally anything* with it if needed.
* EXCEPT IF I WANT TO USE AN ENUM/TYPE AS A KEY IN AN DICT WHICH I REALLY WANT TO DO!!
> - Tagged template strings. This just feels dirty to me. Probably won't use, but when I see it in a code base I won't be so confused at least
Tagged template strings are an absolutely brilliant feature and have tons of valuable uses. In particular, many sql libraries in node let you do this:
const query = sql`select foo from bar where zed = ${param}`;
From a developer standpoint it "feels" just like you're doing string concatenation, but in reality the query variable will contain a prepared statement so that it safely prevents any kind of SQL injection, e.g. it gets parsed to
{
sql: "select foo from bar where zed = ?",
parameters: [param]
}
There are lots of use cases where things are easily expressed as an interpolated string, but the thing you want back is NOT just a plain string, and tagged template literals are great for that. It's also a nice way to call a parser, e.g. many GraphQL libraries let you do:
const parsedGraphQLSchema = gql`type Query { foo: Int }`;
> - # private... not sure why they didn't just use the "private" keyword, but I don't care. I almost always use TypeScript anyways
One of the reasons was to allow private and public fields of the same name, so that subclasses are free to add own public fields without accidentally discovering private fields of superclasses. There were many more considerations that went into the design: https://github.com/tc39/proposal-class-fields/blob/main/PRIV....
> - Tagged template strings. This just feels dirty to me. Probably won't use, but when I see it in a code base I won't be so confused at least
What's funny is the go-to example of using it for translations is just wrong: It only does numeric indexing, so can't be reliably used with languages where words would be in a different order. You still need a library or something that builds on top of it to handle that.
"??=, &&=, ||=" Yes they are, i stuck always when i see them.
I think we just need more practice and need to see them more often until it becomes normal. Currently i avoid to use them.
> - Promise.allSettled. THIS is useful. I've implemented this (under a different name) in almost every code base I've worked on, and got bit HARD by not understanding this behavior long ago (huge production outage that took hours and many engineers to discover)
You and your team didn't understand how Promise.allSettled behaved?
Object.hasOwn(obj, name): Finally! That took long. Why would you even think that obj.hasOwnProperty(name) would be ok? If its unclear what properties there are you can't expect that the hasOwnProperty property to be working correctly. Always had to do the Object.prototype.hasOwnProperty.call(obj, name) dance.
As a swe that works with typescript / javascript, I find this post exhausting.
Am I the only one? Am I a shit swe?
Edit - comments seem to suggest I was asking this question seriously. I was not, I was just (sort of) joking.
That being said, front end engineering is rapidly changing all the time, so the confidence I have in knowing I will always have work to do (read that to mean: a job) is satisfying.
I don't find it exhausting. There's some stuff I already use, some I'll remember, some I'll forget, and one day I'll probably google for one of these features, but until then it's not going to weigh on me.
I don't think it's that bad but I wish they'd focus more on improving the terrible JS web API rather than adding language features.
I mean they are adding features like static initialisation blocks when we only just got String.replaceAll(), and they somehow managed to fuck that API up despite it being explicitly a replacement for an existing bad API!
Where are all the containers? Sorted sets/maps? Why can't I even map an iterator?
I think one can both learn about the new features without feeling the need to use them all or refactor old code.
My biggest learning while writing this was just how much is possible in JavaScript and TypeScript now, but I also realize that a lot of this I will not use myself or only use to understand some really specific code.
It's understandable of you haven't touched JS for a few years. But if you work with JS/TS a lot and are not aware of/already using many of the features listed here, you need to ask yourself (or maybe your company) if that's ok. A lot of these are very nice features that are used daily -- they help code to be cleaner and more concise, and you can work more productively.
You're certainly not the only shit SWE if you are one. I used to be a good all-rounder, but I've stagnated badly for years everywhere but the database. I should probably have shuffled to management (I understand more than I can do!) but I hate the very idea.
Not to be the perpetual Luddite, but I hate how much programming languages change. I don’t particularly like go as a language (good board game though), but the minimal changes over time starts to feel really correct.
For me, the most awesome and useful change to Javascript has been the addition of private and static modifiers, although the implementation is kinda weird (why use “static” keyword but not “private” and the # sigil instead?). I use both TS and JS professionally but much prefer native JS and use it in my personal projects, however, the closer native JS can get to TS, the better, as I really do appreciate many of it’s features.
"
Negative indexing (.at(-1)): When indexing an array or a string, at can be used to
index from the end. It’s equivalent to arr[arr.length - 1)
"
sic arr[arr.length-1)
This is wrong. Array.at can get, but not set the value. So they're not equivalent.
console.log( arr[arr.length-1] ); // works
arr[arr.length-1] = 1; // works
console.log( arr.at(-1) ); // works
arr.at(-1) = 1; // ReferenceError: Invalid left-hand side in assignment
Is it me or are Tagged templates a recipe for hard to read code?
Just the way it extracts the substrings into arguments for unpredictable strings. It doesn't translate to readable code.
I'd much rather use repetitive template strings. Unless I was doing some really fancy string manipulation. Or make my own functions with explicit arguments.
Not mentioned: importmap is supported in Firefox as of February. Also supported in Chrome and upcoming for Safari. Just in time as I finally started getting more into cutting edge JS with a personal project - job's been stuck on older JS for a long time and I haven't done personal projects in just as long.
I've been running this project straight in the browser with no JS compiler. Are JS compilers going to be on the way out now?
Is there a complete list of proper modern JavaScript features and examples covering all and only the features and styles which are modern (not neccesarily this new, perhaps some are 4-year-old) and relevantant + those which have never been replaced by any newer so are sill relevant although old but excluding outdated features and styles?
If you asked me what the biggest areas were where JS needs work, it wouldn't be "syntax sugar for separating numeric literals", it would be stuff like "integers".
At this point I'm almost afraid to ask, but if JS can evolve in major ways like this, why can't we address some of the basic shortcomings of the language?
[+] [-] jakubmazanec|3 years ago|reply
[+] [-] Waterluvian|3 years ago|reply
[+] [-] pharmakom|3 years ago|reply
[+] [-] jjnoakes|3 years ago|reply
https://www.typescriptlang.org/play#code/MYewdgziA2CmB00QHMA...
[+] [-] sph|3 years ago|reply
There are people ready to defend with their life the most obtuse, inane piece of technology, just because they have invested a non-negligible amount of time getting used to its quirks, that they become completely blind to its faults, and start to believe those very quirks are actually positive and to be cherished.
[+] [-] mattpallissard|3 years ago|reply
This is alludes to my only major complaint about typescript. IMO, something is either type-safe or it ain't. I don't like how the JS bleeds through if you aren't careful.
I'm not a TS hater by any means, I use it regularly and am usually pleased. I just can't help but compare it to the [S,Oca]ML compilers I'm so fond of.
[+] [-] DarkNova6|3 years ago|reply
It took a long time for js devs to accept the notion of a compiler with TS. While TS is an improvement, it’s only a localized one. No chance ever, any other language could have replaced it.
[+] [-] moltar|3 years ago|reply
[+] [-] Ezku|3 years ago|reply
[+] [-] itslennysfault|3 years ago|reply
- Tagged template strings. This just feels dirty to me. Probably won't use, but when I see it in a code base I won't be so confused at least
- matchAll. I've never needed this. I've used match with g a bunch, but I never need the capture group.
- Promise.allSettled. THIS is useful. I've implemented this (under a different name) in almost every code base I've worked on, and got bit HARD by not understanding this behavior long ago (huge production outage that took hours and many engineers to discover)
- globalThis. EW. Don't think I have to elaborate
- replaceAll. It's always annoyed me needing to use RegEx for simple replace all. so Yay!
- ??=, &&=, ||= These seem really useful, but also potentially hard to read, but I think if I get used to their existence they'd become second nature
- # private... not sure why they didn't just use the "private" keyword, but I don't care. I almost always use TypeScript anyways
- static ... YAY! finally. Again, if they could do this i don't see why not "private"
For the TypeScript stuff I'll just say the type system has kinda jumped the shark, but I don't hate it. It's SO robust and of all the new stuff being added I'll maybe use 1/10 of it, but it's good to know I can describe literally anything* with it if needed.
* EXCEPT IF I WANT TO USE AN ENUM/TYPE AS A KEY IN AN DICT WHICH I REALLY WANT TO DO!!
[+] [-] hn_throwaway_99|3 years ago|reply
Tagged template strings are an absolutely brilliant feature and have tons of valuable uses. In particular, many sql libraries in node let you do this:
From a developer standpoint it "feels" just like you're doing string concatenation, but in reality the query variable will contain a prepared statement so that it safely prevents any kind of SQL injection, e.g. it gets parsed to There are lots of use cases where things are easily expressed as an interpolated string, but the thing you want back is NOT just a plain string, and tagged template literals are great for that. It's also a nice way to call a parser, e.g. many GraphQL libraries let you do:[+] [-] stasm|3 years ago|reply
One of the reasons was to allow private and public fields of the same name, so that subclasses are free to add own public fields without accidentally discovering private fields of superclasses. There were many more considerations that went into the design: https://github.com/tc39/proposal-class-fields/blob/main/PRIV....
There was a heated debate about this and the choice of the # sigil back in 2015 at the time private fields were being designed: https://github.com/tc39/proposal-private-fields/issues/14.
[+] [-] treis|3 years ago|reply
It's better just to use an actual array for enums:
myEnum = ["E1", "E2"...] as const
type myEnum = typeof myEnum[number]
That gets you both an enum type and an enum array you can use at runtime
[+] [-] anamexis|3 years ago|reply
[+] [-] maxpowa|3 years ago|reply
[+] [-] 5Qn8mNbc2FNCiVV|3 years ago|reply
Then instantiate like:
``` { [EnumType.First]: ..., [EnumType.Second]: ... } ```
[+] [-] Izkata|3 years ago|reply
What's funny is the go-to example of using it for translations is just wrong: It only does numeric indexing, so can't be reliably used with languages where words would be in a different order. You still need a library or something that builds on top of it to handle that.
[+] [-] tengbretson|3 years ago|reply
[+] [-] manv1|3 years ago|reply
When I first started using node way back when I discovered all kinds of idioms in use that I had never seen. It was a confusing few weeks for sure.
[+] [-] progx|3 years ago|reply
[+] [-] cagmz|3 years ago|reply
You and your team didn't understand how Promise.allSettled behaved?
[+] [-] illiarian|3 years ago|reply
A while back I wrote that "Tagged Template Literals Are the Worst Addition to Javascript" https://dmitriid.com/blog/2019/03/tagged-template-literals/ and I still stand by it.
The fact that someone uses them in a somewhat nice fashion in an sql library doesn't change the fact
[+] [-] manv1|3 years ago|reply
Negative indexes might actually be useful.
At some point I actually need to read the actual language specs, I guess.
[+] [-] panzi|3 years ago|reply
[+] [-] transitivebs|3 years ago|reply
[+] [-] Killusions|3 years ago|reply
[+] [-] game_the0ry|3 years ago|reply
Am I the only one? Am I a shit swe?
Edit - comments seem to suggest I was asking this question seriously. I was not, I was just (sort of) joking.
That being said, front end engineering is rapidly changing all the time, so the confidence I have in knowing I will always have work to do (read that to mean: a job) is satisfying.
[+] [-] __ryan__|3 years ago|reply
If you find yourself struggling to articulate it, seriously and honestly consider whether you’re simply choosing to be stressed about it.
I’m speaking from experience here.
[+] [-] SketchySeaBeast|3 years ago|reply
[+] [-] IshKebab|3 years ago|reply
I mean they are adding features like static initialisation blocks when we only just got String.replaceAll(), and they somehow managed to fuck that API up despite it being explicitly a replacement for an existing bad API!
Where are all the containers? Sorted sets/maps? Why can't I even map an iterator?
[+] [-] Killusions|3 years ago|reply
My biggest learning while writing this was just how much is possible in JavaScript and TypeScript now, but I also realize that a lot of this I will not use myself or only use to understand some really specific code.
[+] [-] rwalle|3 years ago|reply
[+] [-] dspillett|3 years ago|reply
[+] [-] jenadine|3 years ago|reply
Why not? I was told the opposite: now that the feature is in JS natively, it can be used.
[+] [-] nickpeterson|3 years ago|reply
[+] [-] synergy20|3 years ago|reply
https://www.javascripttutorial.net/es-next/
[+] [-] temporallobe|3 years ago|reply
[+] [-] jankovicsandras|3 years ago|reply
This is wrong. Array.at can get, but not set the value. So they're not equivalent.
console.log( arr[arr.length-1] ); // works
arr[arr.length-1] = 1; // works
console.log( arr.at(-1) ); // works
arr.at(-1) = 1; // ReferenceError: Invalid left-hand side in assignment
[+] [-] Killusions|3 years ago|reply
[+] [-] dmix|3 years ago|reply
Just the way it extracts the substrings into arguments for unpredictable strings. It doesn't translate to readable code.
I'd much rather use repetitive template strings. Unless I was doing some really fancy string manipulation. Or make my own functions with explicit arguments.
[+] [-] jimmaswell|3 years ago|reply
I've been running this project straight in the browser with no JS compiler. Are JS compilers going to be on the way out now?
[+] [-] rwalle|3 years ago|reply
[+] [-] qwerty456127|3 years ago|reply
[+] [-] t8sr|3 years ago|reply
At this point I'm almost afraid to ask, but if JS can evolve in major ways like this, why can't we address some of the basic shortcomings of the language?
[+] [-] Andrex|3 years ago|reply
14-year old me hacking up my first JS on Freewebs.com is doing backflips right now.
...And 31-year old me is saying "What the fuck took them so long?"
[+] [-] delaaxe|3 years ago|reply
[+] [-] k__|3 years ago|reply