[HN Gopher] JavaScript and TypeScript features of the last 3 years
       ___________________________________________________________________
        
       JavaScript and TypeScript features of the last 3 years
        
       Author : Killusions
       Score  : 308 points
       Date   : 2023-03-09 10:35 UTC (12 hours ago)
        
 (HTM) web link (medium.com)
 (TXT) w3m dump (medium.com)
        
       | jenadine wrote:
       | > #private: [...] This is not recommended for TypeScript
       | projects, instead just use the existing private keyword.
       | 
       | Why not? I was told the opposite: now that the feature is in JS
       | natively, it can be used.
        
         | conaclos wrote:
         | The Deno style guide encourages the use of `#prop` over
         | `private prop` [0]. Other guides such as the Google TypeScript
         | Guide discourages their use [1] for now because they are
         | transpiled to slow code.
         | 
         | What I could conclude is: use `#` over `private` for runtimes
         | that support them or projects that can target recent runtimes
         | and browsers.
         | 
         | [0]
         | https://deno.land/manual@v1.29.3/references/contributing/sty...
         | 
         | [1] https://google.github.io/styleguide/tsguide.html#private-
         | fie...
        
       | Killusions wrote:
       | I took the time to explain all the latest (and some older)
       | JavaScript and TypeScript changes, including code examples.
        
         | matthewmueller wrote:
         | Thanks for doing this! I found this post very helpful to get
         | exposed to recent changes from the last couple years.
        
         | mook wrote:
         | Looked up on MDN (and from there the ES spec), import
         | assertions don't seem to actually be standard. You might want
         | to mark that somehow (or drop it).
        
           | Killusions wrote:
           | You are correct, I added a note.
        
         | tobr wrote:
         | Symbols are not an ES2022 feature. I believe they were
         | introduced in ES2015.
        
           | Killusions wrote:
           | Just looked it up, you are of course correct. I will move
           | them into the "Past" part.
        
       | transitivebs wrote:
       | We need an equivalent "All AI breakthroughs in the last week
       | explained"
        
         | yieldcrv wrote:
         | @eluna.ai posts summaries on ig
        
         | btown wrote:
         | Two Minute Papers is a relatively good proxy for this!
         | https://www.youtube.com/channel/UCbfYPyITQ-7l4upoX8nvctg
        
           | hungryforcodes wrote:
           | "Two Minute Papers"...
           | 
           | ...ironically in video format.
        
             | gs17 wrote:
             | That's not ironic to me, the intent seemed to be "papers
             | presented in two minutes", although maybe there's some
             | irony in exceeding that length in every video?
        
             | satvikpendem wrote:
             | What is the irony?
        
               | manv1 wrote:
               | a paper in video format?
               | 
               | I actually hate videos, it's easier for me to read than
               | to listen to someone taking 5 minutes to explain a
               | paragraph's worth of stuff.
               | 
               | "It's longer because monetization."
        
               | satvikpendem wrote:
               | How is that ironic? I wonder if people actually know the
               | meaning of irony these days.
        
           | daavidhauser wrote:
           | too bad i simply can't stand the way he talks :( am i the
           | only one?
        
             | melling wrote:
             | Something grating going on with him. I think it might be
             | the way he tries to make it sound exciting for a general
             | audience.
        
               | jasode wrote:
               | _> I think it might be the way he tries to make it sound
               | exciting for a general audience._
               | 
               | Looking at other videos of Karoly Zsolnai-Feher speaking
               | at a podium to an audience, I think he's genuinely
               | enthusiastic about the subject instead of putting on an
               | act. However, when combining that unusual enthusiasm with
               | a Hungarian accent, some listeners may find it odd
               | sounding.
               | 
               | Example vid:
               | https://www.youtube.com/watch?v=-JdmOBA0WQ0&t=1m49s
        
             | Cthulhu_ wrote:
             | Probably not, I dislike video / audio as a means to explain
             | and update things, I'll watch the news (because the video
             | adds to the story) but I'd rather have a text version if
             | it's about software things.
        
         | satvikpendem wrote:
         | My friend runs a newsletter called Bot Eat Brain which is
         | precisely this.
         | 
         | https://www.boteatbrain.com/
        
       | temporallobe wrote:
       | 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.
        
         | starik36 wrote:
         | The # for private throws me every time I look at my code.
         | Keyword "private" would have been so much cleaner and in line
         | with most programming languages out there.
        
         | kipple wrote:
         | The # sigil has always bummed me out too.
         | 
         | Supposedly it's because of this:
         | 
         | > Why isn't access this.x?
         | 
         | > Having a private field named x must not prevent there from
         | being a public field named x, so accessing a private field
         | can't just be a normal lookup.
         | 
         | https://github.com/tc39/proposal-class-fields/blob/main/PRIV...
         | 
         | Combined with this:
         | 
         | > Why aren't declarations private x?
         | 
         | > This sort of declaration is what other languages use (notably
         | Java), and implies that access would be done with this.x.
         | Assuming that isn't the case (see above), in JavaScript this
         | would silently create or access a public field, rather than
         | throwing an error. This is a major potential source of bugs or
         | invisibly making public fields which were intended to be
         | private.
         | 
         | https://github.com/tc39/proposal-class-fields/blob/main/PRIV...
         | 
         | But I still think it's weird.
        
           | illiarian wrote:
           | Because they awkwardly bolted C++-like class syntax on top of
           | prototype-based language and are now fighting that.
           | 
           | Same goes for methods that you have to manually bind to
           | `this` in the constructor etc.
           | 
           | It literally is one of the "they didn't think if they should"
           | parts of the language.
        
       | nickpeterson wrote:
       | 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.
        
         | dayvid wrote:
         | If it's any consolation, the guy from nomadlist is building AI
         | businesses with jQuery and PHP:
         | https://twitter.com/levelsio/status/1633422349012992007
        
           | wiseowise wrote:
           | How does it work, though?
        
         | svachalek wrote:
         | I'm more annoyed that the direction of change is mostly
         | converging. Maybe that's a good thing, but it seems every
         | language needs to add every popular feature of other languages
         | until it's possible to code any language as any other language
         | except in incompatible syntax.
         | 
         | In the case of TypeScript, we have the base JavaScript,
         | template literals, and the type system all playing this game in
         | the same file. Three systems trying to out feature each other.
         | Tagged template literals, template literal types, etc.
        
           | AprilArcus wrote:
           | Template literal types (a) have nothing to do with tagged
           | template literals, and (b) are a game-changing feature,
           | allowing you to write compile-time string parsers.
        
             | Aeolun wrote:
             | > allowing you to write compile-time string parsers
             | 
             | I'm not entirely sure this is a good thing. But it's
             | certainly convenient in some instances.
        
               | rcfox wrote:
               | I, for one, love that my ORM can statically check my SQL
               | statements.
        
               | eyelidlessness wrote:
               | It's a cutesy thing that _basically always_ comes with a
               | "don't actually do /use this!" disclaimer. The thing
               | that's actually good about template literal types is that
               | they allow for modeling a whole class of real world JS
               | that wasn't possible otherwise. That is and always has
               | been the fundamental goal of TS.
        
         | Cthulhu_ wrote:
         | I don't think the issue is that languages change per se - it's
         | that they borrow features from other languages, that people ask
         | "can we have $feature from $language please?"
         | 
         | in JS (and years before that, PHP), one example was object-
         | oriented programming / classes, except in both JS and PHP it
         | was never implemented fully, with JS not even having access
         | modifiers for a long time. JS didn't need classes and the
         | implementation is lacking, but someone decided it should be
         | added.
         | 
         | Likewise, Java had functional programming bolted on; they never
         | extended the base List types with functional modifiers, so now
         | you have to transform or wrap your List in a Stream to make it
         | work with Java's attempts at functional programming.
         | Personally, I think if you want to do FP or FP-style coding on
         | the JVM, you should rewrite things in Scala. You can write
         | Scala and Java side-by-side.
         | 
         | Same with JS, you want JS but with types? You can have
         | Typescript. I wish they did the same with JS-with-classes, just
         | write a new language that compiles to JS instead of bolt
         | classes onto the JS standard.
        
           | chime wrote:
           | > I wish they did the same with JS-with-classes, just write a
           | new language that compiles to JS instead of bolt classes onto
           | the JS standard.
           | 
           | Jeremy tried https://arcturo.github.io/library/coffeescript/0
           | 3_classes.ht...
        
           | yamtaddle wrote:
           | > I wish they did the same with JS-with-classes, just write a
           | new language that compiles to JS instead of bolt classes onto
           | the JS standard.
           | 
           | I think the classes were a good thing. Better would have been
           | to change the OO model entirely, but if you're going to have
           | one and can't change it, nice to at least have some sugar to
           | make it usable. IDK if it's better elsewhere, but prototypal
           | OO was pretty clearly a miss-step for Javascript, and sugar
           | to make the OO system usable and less-obtuse (while making it
           | easier to ignore the parts that should basically never be
           | used, which parts amount to _all_ the distinctive things
           | about prototypal OO) is a decent move.
        
           | specialist wrote:
           | My second love was LISP. I love me some functional
           | programming.
           | 
           | But I greatly dislike multi-paradigm programming languages.
           | Mostly because I've worked with other programmers.
           | 
           | Borrowing features (idioms) from other languages is great.
           | Pattern matching is nice. For Java, I'm looking forward to
           | (interpolated) string templates and implicit classes.
           | Destructuring would be nice too.
           | 
           | --
           | 
           | But for the love of Larry, where are intrinsic regex
           | expressions?
           | 
           | Path expressions?
           | 
           | Most of our work is data processing.
           | 
           | Input -> munging -> output.
           | 
           | Meaning cutting and pasting strings.
           | 
           | So I mostly want new features related to string and data
           | processing.
           | 
           | --
           | 
           | The evergreen fetish (kink) with arcana like type systems,
           | monads, and metaprogramming is just so besides the point.
           | That's what Lambda the Ultimate and HN are for.
           | 
           | For "commercial" languages, just give me tools for work.
           | 
           | Fussing with novel languages is for my hobby projects.
        
           | pcthrowaway wrote:
           | > Same with JS, you want JS but with types? You can have
           | Typescript. I wish they did the same with JS-with-classes,
           | just write a new language that compiles to JS instead of bolt
           | classes onto the JS standard.
           | 
           | Wow, relevant username for this take, as you'd end up with an
           | eldritch creature as soon as people tried to bolt these DSLs
           | together into _their_ opinionated bags of features, and a
           | meta-language landscape that resembles the already fragmented
           | frontend landscape of today
        
         | steve_adams_86 wrote:
         | Go helped me realize that how much you like a language can
         | partially be a function of how you try to use it.
         | 
         | I used Go wrong for years. Once I stopped doing dumb stuff with
         | it (especially with the type system), it got a lot more
         | pleasant. I don't think I'd design it the same way, but I'm
         | quite a bit happier using it now.
         | 
         | It's kind of like using a hammer to drive a screw. The problem
         | isn't the screw or the hammer. Go seems to be a hammer-screw
         | situation for a lot of people, but there really is a happy
         | path.
         | 
         | Not saying this because I think you're unaware -- mostly
         | thinking out loud because I used to feel like Go needed new
         | features and your comment reminded me of this. I also like the
         | relative stability of Go now, though. It has a great
         | foundational toolset and good design overall, so to its credit,
         | it hasn't really needed to change so much. I only thought it
         | did because I used it wrong.
        
         | packetlost wrote:
         | C doesn't seem to have substantially changed in 20+ years.
        
           | flohofwoe wrote:
           | The C99 changes were pretty radical, but couldn't be broadly
           | used until around 2016 when the Microsoft compiler finally
           | caught up and started to implement the most important C99
           | features.
        
             | kevin_thibedeau wrote:
             | C11 provides a lot of useful goodies too. I don't relish
             | the idea of writing C89 and giving up all the improvements.
        
           | RobotToaster wrote:
           | C23 adds support for type inference.
        
         | djtriptych wrote:
         | To be fair, now that almost all professionally-written passes
         | through a rewriting compiler, Javascript actually has evolved
         | to a ecosystem that _can_ handle rapid (non-breaking) changes
         | to a language spec.
         | 
         | I'd also argue that the majority of these changes are to the
         | standard library (new methods on String, Array, RegExp, etc).
         | Not really core language changes. I don't know how often the go
         | libs update but surely faster than the language spec?
        
           | avgcorrection wrote:
           | > To be fair, now that almost all professionally-written
           | passes through a rewriting compiler,
           | 
           | What?
        
             | djtriptych wrote:
             | To add the above - I also meant to write "Professionally-
             | written Javascript" in case it was the grammar that threw
             | you off. Sorry!
        
             | HeavyFeather wrote:
             | They're likely referring to Babel and TypeScript. In short,
             | it doesn't matter what you're writing as long as your
             | transpiler has the right `target` so it works in older
             | browsers/engines too.
        
             | bitwize wrote:
             | There are popular JavaScript tools that nearly everyone
             | uses, that reimplement Lisp poorly by source-to-source
             | compiling stuff written against the latest new hotness spec
             | into something that can be run by some old-and-busted
             | JavaScript runtime (e.g., in browsers).
             | 
             | In fact this is how TypeScript is implemented.
        
         | bryanlarsen wrote:
         | The changes aren't breaking. Javascript from the 90's still
         | works.
        
       | game_the0ry wrote:
       | 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.
        
         | rwalle wrote:
         | 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.
        
         | __ryan__ wrote:
         | It's exhausting because: _____
         | 
         | 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.
        
         | IshKebab wrote:
         | 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?
        
           | HeavyFeather wrote:
           | > focus more on improving the terrible JS web API
           | 
           | That's W3C's job, not ECMA's.
           | 
           | > Where are all the containers?
           | 
           | ?
           | 
           | > Sorted sets/maps?
           | 
           | Sets and Maps _are_ sorted (by insertion order)
           | 
           | > Why can't I even map an iterator?
           | 
           | It's coming, but someone will likely be _exhausted_ by that
           | addition. https://github.com/tc39/proposal-iterator-helpers
        
             | IshKebab wrote:
             | > Sets and Maps are sorted (by insertion order)
             | 
             | That's not what a "sorted set" is. C++ and Rust provide
             | sets (and maps) that sort based on an arbitrary comparison
             | operator.
             | 
             | > ?
             | 
             | ?
             | 
             | > but someone will likely be exhausted by that addition
             | 
             | I suppose. I guess it's one of those things that they
             | really should have got right the first time. Like
             | String.replaceAll(). I guess they will never add
             | String.replaceAllSafe() - well just have to rely on linters
             | to tell us that the API is terrible forever.
        
             | TheCoelacanth wrote:
             | By sorted sets/maps, I think they are referring to a
             | binary-search-tree-backed implementation that is efficient
             | for operations like find all keys between x and y, e.g.
             | something like Java's SortedSet[1].
             | 
             | [1] https://docs.oracle.com/javase/7/docs/api/java/util/Sor
             | tedSe...
        
         | Killusions wrote:
         | 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.
        
         | dspillett wrote:
         | 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.
        
         | SketchySeaBeast wrote:
         | 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.
        
           | Accacin wrote:
           | Yeah I'm the same. I try not to worry and learn everything,
           | but I try and at least read on new changes just so I'm
           | familiar with them.
           | 
           | Then when I see it in the code, I'll know what it does or
           | I'll be like "Oh wait, that new feature I read about, maybe
           | that could be of use here".
           | 
           | I'm never going to remember everything and I'm okay with that
           | :)
        
       | jimmaswell wrote:
       | 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?
        
         | rwalle wrote:
         | Import map is an HTML feature and not in any JavaScript
         | specification. JavaScript language does not care about how to
         | find files.
        
       | k__ wrote:
       | Are * and default the same?
        
         | AprilArcus wrote:
         | `*` is the namespace object. `default` is a special named
         | property on the namespace object.
         | 
         | someModule.js:                   export default 'foo';
         | export const bar = 'bar';
         | 
         | namespaceImport.js:                   import * as SomeNamespace
         | from './someModule.js';
         | console.assert(SomeNamespace.default === 'foo');
         | console.assert(SomeNamespace.bar === 'bar');
         | 
         | defaultImport.js:                   import foo from
         | './someModule.js';         console.assert(foo === 'foo');
         | 
         | namedImports.js:                   import { default as foo, bar
         | } from './someModule.js';         console.assert(foo ===
         | 'foo');         console.assert(bar === 'bar');
        
           | HeavyFeather wrote:
           | Note that there's an error on the default export:
           | - export default foo = 'foo';         + export default 'foo';
        
             | AprilArcus wrote:
             | thanks, fixed
        
               | jenadine wrote:
               | A lot of 'x1' should be 'x2' in the examples
        
         | [deleted]
        
         | shadowgovt wrote:
         | Can you clarify the question? In what sense are you asking if
         | they're the same / not the same?
         | 
         | In general, `import * from X` will pull every exported symbol
         | of X into your current module at the top level (generally not
         | recommended except for special cases like testing libraries;
         | you shackle yourself to an assumption that the imported module
         | won't ever add new symbols that might interact surprisingly
         | with the importing module). `import * as Y from X` is slightly
         | safer; it'll pull in all the exported symbols from X, but will
         | wrap them in a Y namespace (so X's `foo` function is now
         | `Y.foo`, etc.). `import {foo} from X` will just import the
         | `foo` symbol from X and make it available in your module.
         | Finally, `import foo from X` imports the single export in X
         | that is tagged as default and names it `foo` in your module.
         | 
         | (To my money, I don't like defaults very much. I much prefer
         | `import {foo} from X` over `import foo from X` for clarity,
         | even if `foo` is the only symbol X exports. It allows for
         | future growth of X and avoids the unsightly `import foo, {bar}
         | from X` that some modules end up growing in the future).
        
         | FrontAid wrote:
         | No. The former imports _all_ the exports, and the latter
         | imports the _default_ export only.
         | 
         | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
         | 
         | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
        
       | delaaxe wrote:
       | There must be a mistake in the "Exact Optional Property Types"
       | section?
        
       | synergy20 wrote:
       | There is another list with concise code samples
       | 
       | https://www.javascripttutorial.net/es-next/
        
       | itslennysfault wrote:
       | 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!!
        
         | tengbretson wrote:
         | Regarding your last point, I think the general consensus in
         | TypeScript is to avoid using enums entirely.
        
         | anamexis wrote:
         | I've used globalThis for polyfills in code that needs to run
         | both in the browser and on node.
        
         | treis wrote:
         | >* EXCEPT IF I WANT TO USE AN ENUM/TYPE AS A KEY IN AN DICT
         | WHICH I REALLY WANT TO DO!!
         | 
         | 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
        
         | illiarian wrote:
         | > 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
         | 
         | 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
        
         | maxpowa wrote:
         | WRT Enum as key in object:                 enum TestEnum {
         | Fizz = 0,         Buzz,         Bar,         Baz       }
         | type EnumKeyedObject = Record<TestEnum, string>;
         | type EnumKeyedObjectAlt = { [P in TestEnum]: string };
        
           | mjhay wrote:
           | That's still awkward and confusing for what would be one of
           | the most common use-cases, if it were less awkward.
        
             | throwanem wrote:
             | How would you simplify the syntax here?
        
         | stasm wrote:
         | > - # 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....
         | 
         | 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.
        
         | Izkata wrote:
         | > - 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.
        
           | edflsafoiewq wrote:
           | Realistically changing word order isn't enough for
           | translation either, you need a special language like ICU
           | message syntax so you can handle grammatical number, gender,
           | etc.
        
         | hn_throwaway_99 wrote:
         | > - 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 }`;
        
           | fulafel wrote:
           | Is it really an good thing that a vulnerable sql string
           | interpolation code pattern and this sql tagged string look
           | and feel the same?
        
             | sanitycheck wrote:
             | I was thinking the same thing... If I do that I'm going to
             | forget the "sql" part at least once and nothing's going to
             | alert me about it.
        
               | hn_throwaway_99 wrote:
               | The way libraries work it's impossible to forget the
               | "sql" part and still have that query be executed - see my
               | sibling comment.
        
             | hn_throwaway_99 wrote:
             | Actually, yes, it is. The way these libraries work, since
             | the thing that is parsed is NOT just a plain string, in
             | most cases it's _impossible_ to have sql injection without
             | doing some deliberately nasty stuff. That is, you can 't
             | just do this:                   const query = `select foo
             | from bar where zed = ${param}`; // forgot the sql tag
             | await runQuery(query);
             | 
             | In that case, the type of query is just string, but the
             | `runQuery` method doesn't take strings, it takes a parsed
             | query, so that wouldn't work.
             | 
             | After using the tagged template literal pattern for SQL
             | queries exclusively for the past couple years, I can't say
             | enough how awesome it is to use in practice. Libraries even
             | let you do strong typing with TypeScript to define the
             | expected structure of the result, e.g.
             | sql<MyExpectedReturnType>`select foo from bar where zed =
             | ${param}`
        
               | conaclos wrote:
               | > Libraries even let you do strong typing with TypeScript
               | to define the expected structure of the result.
               | 
               | The tagged template does not return a string in this
               | case?
        
             | runarberg wrote:
             | Why wouldn't it be? Do you think developers get inspired by
             | this slick API and decide to write functions that talk
             | directly to the database using unescaped interpolated
             | strings? I doubt it.
        
           | idoubtit wrote:
           | I fear that syntactic sugar creates as many problems as it
           | solves. For instance, one might wish to sort the results by
           | whitelisted column:                   query = sql`select foo
           | from bar where zed = ${p} order by ${col} asc`;
           | 
           | Unless the lib implements a real SQL parser for the right
           | dialect, it will quote each expression in the same way, and
           | will either fail or produce a broken SQL.
        
             | hn_throwaway_99 wrote:
             | Definitely a lot of misconceptions around how this would
             | work. Just check out something like slonik,
             | https://github.com/gajus/slonik, which is an excellent
             | implementation.
             | 
             | The example you gave actually isn't valid, because what
             | you're doing is generating SQL dynamically, and that
             | doesn't work the way prepared statements work. That is, you
             | can't have a prepared statement like "select foo from bar
             | where zed = ? order by ? asc", because with prepared
             | statements the question marks can only substitute for
             | VALUES, not schema names. So if you wanted to do something
             | like that it slonik, it would fail. With slonik you CAN do
             | dynamic SQL, that is guaranteed to be safe and checked at
             | compile time with TypeScript, because you can nest SQL
             | tagged templates. That is you can do this:
             | const colToSortBy = useFoo ? sql`foo` : sql`bar`;
             | const query = sql`select col from mytable order by
             | ${colToSortBy}`;
             | 
             | In that case slonik will know how to safely "merge" the
             | parent and child parsed SQL.
        
         | progx wrote:
         | "??=, &&=, ||=" 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.
        
         | manv1 wrote:
         | "when I see it in a code base I won't be so confused at least"
         | 
         | 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.
        
         | 5Qn8mNbc2FNCiVV wrote:
         | Isn't Record<EnumType, whatever> working?
         | 
         | Then instantiate like:
         | 
         | ``` { [EnumType.First]: ..., [EnumType.Second]: ... } ```
        
           | hn_throwaway_99 wrote:
           | Yep, do this all the time. It's also really nice because when
           | you define a type as                   Record<EnumType, any>
           | 
           | then when you are creating an instance of that Record object,
           | it requires a key for _all_ the EnumType values, and will
           | fail if you forgot one. Still possible to do
           | Partial<Record<EnumType, any>>
           | 
           | if you want the keys to be only of the EnumType, but don't
           | require all the EnumType values to be used as a key in the
           | Record.
        
       | jakubmazanec wrote:
       | 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...).
        
         | Waterluvian wrote:
         | Typescript is one of those things that makes me so productive
         | that I have absolutely nothing to argue or prove. Their loss.
        
           | RadiozRadioz wrote:
           | Not a rebuttal, just curious, how do you find your
           | productivity compares to a "real" statically typed language
           | (e.g. Go, Java, etc.)? Does your increase in productivity
           | compared to JavaScript simply come from static typing, or is
           | TypeScript itself the source?
        
       | t8sr wrote:
       | 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?
        
         | rwalle wrote:
         | I develop with JavaScript professionally and I rarely think
         | about floating point number/integers when building UI or
         | Node.js code. The "number" type is good enough in 99% of use
         | cases. If you really need integers, there are specialized uint
         | arrays and BigInt that handle various use cases.
        
         | johnfn wrote:
         | Is BigInt not what you want? https://developer.mozilla.org/en-
         | US/docs/Web/JavaScript/Refe...
        
           | Killusions wrote:
           | Ironically this is the only JavaScript change (except for top
           | level await) I did not include, maybe I'll edit it and add
           | it.
        
             | pcthrowaway wrote:
             | Those are 2 of the most significant (and eagerly awaited)
             | new(er) features though (although I thought BigInt was more
             | like 5-6 years old)
             | 
             | edit: Edge and Safari only added support in 2020, so it has
             | only been useable without polyfills for a few years
        
       | qwerty456127 wrote:
       | 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?
        
         | Killusions wrote:
         | I haven't found one yet, but I'm sure there's one somewhere out
         | there. I will try to keep updating this article so someday it
         | will be what you're looking for.
        
         | schemescape wrote:
         | I'm not sure if this matches what you want, but I made a note
         | of this site when I ran across it for a similar reason:
         | 
         | https://javascript.info/
        
         | FrontAid wrote:
         | Can you make an example of features/styles that have been
         | replaced? I'm not really sure what you mean by that.
        
           | qwerty456127 wrote:
           | Others have provided great examples of what I meant.
        
           | mordechai9000 wrote:
           | As an example, the immediately invoked function expression
           | (IIFE) has been superseded by ES 6 modules.
        
           | tofuahdude wrote:
           | The classic example is .then .catch callbacks vs async await,
           | though .then is still occasionally useful.
        
         | z3t4 wrote:
         | straight legs jeans instead of bell-bottom jeans because less
         | fabric required. Hats have been replaced by caps, or just go
         | without either, because we are mostly inside anyway. We still
         | use suits, but it's not required. Most people use jeans,
         | because SWE's can't afford wool.
         | 
         | Ohh, sorry, you mean JavaScript... const is the new var because
         | Java programmers don't understand function scope. ()=>{} is the
         | new function declaration because many people want to go back to
         | Perl like syntax. class instead of prototype because Java
         | programmers don't understand prototype. TypeScript instead of
         | JavaScript because Java programmers can't live without type
         | annotations and editor autocomplete. async/await instead of
         | Promise because what we can't see (async code) can't hurt us.
         | import instead of require because JetBean intellicense could
         | not autocomplete dynamic require/imports.
        
       | dmix wrote:
       | 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.
        
         | [deleted]
        
         | renlo wrote:
         | They've allowed "styled-components" to work though, which is
         | pretty nice. I always thought of them as providing a way to
         | parse DSLs directly in your code. For example, a fictional way
         | to generate some config could look like this (using tagged
         | templates):                 const thingies = ["a", "b"];
         | const config = yaml`         - foo         - bar         - baz
         | - thingies: ${thingies.map(thing => yaml`- thing: ${thing}`)}
         | `;       // config = ["foo", "bar", "baz", { "thingies":
         | [{"thing": "a"}, {"thing": "b"}] }]
         | 
         | At a company I worked at people were generating YAML using
         | Jinja templates, but tagged templates to me would be a better
         | approach. Is it hard to read? It can be, but compared to the
         | alternatives it's not too bad.
        
           | monkpit wrote:
           | const thingies = ["a", "b"];       const thingToYaml = thing
           | =>          yaml`- thing: ${thing}`       const thingiesYaml
           | =         thingies.map(thingToYaml)            const config =
           | yaml`         - foo         - bar         - baz         -
           | thingies: ${thingiesYaml}       `;
           | 
           | It doesn't have to be hard to read
        
             | shhsshs wrote:
             | In this example, why use YAML at all?...
             | const thingies = ["a", "b"];         const config = [
             | "foo",           "bar",           "baz",           {
             | thingies: thingies.map(thing => ({ thing })),           },
             | ]         // config = ["foo", "bar", "baz", { "thingies":
             | [{"thing": "a"}, {"thing": "b"}] }]
        
           | lloydatkinson wrote:
           | Well, styled components also has a plain object syntax which
           | I think a lot of people prefer me included.
        
         | tobr wrote:
         | Matching up the template strings with the values is a little
         | wonky because there's always one more string than value. But
         | it's pretty rare that you'd write lots of different tagging
         | functions, usually you write a generic one to use with many
         | different types of templates. Tucking away complexity into a
         | function to make nice and easy-to-use templates is a reasonable
         | trade off I think.
        
         | tracker1 wrote:
         | To me, the single best example, is a function that turns a
         | template into a parameterized query, and then makes an async
         | database request...                   var result = await query`
         | SELECT * FROM foo.bar where baz = ${baz}         `;
         | 
         | There are libraries that allow for construction of queries as
         | well using template strings. I don't know of too many instances
         | beyond this where there's custom functions for tagged
         | templates, vs just string building with parameters.
        
           | jmull wrote:
           | I agree this is pretty much the best example of this feature
           | in action... which is why I don't think it should have been
           | made a language feature.
           | 
           | It's nifty, but not nearly better enough to justify its
           | existence, IMO. Here's the alternative:                   var
           | result = await query(             'SELECT * FROM foo.bar
           | where bar = :baz',             {baz}         );
           | 
           | I get it... there's that extra level of indirection. But
           | people are working hard, as we speak, to abuse the feature.
        
             | shhsshs wrote:
             | In this case - the thing I personally value in the template
             | version is I don't have to name the parameters and specify
             | them in a separate place. It's especially useful in larger
             | queries.                   var result = await query(
             | 'SELECT * FROM foo.bar where bar = :baz               --
             | 100 more lines of where clauses, CTEs, etc.             ',
             | {baz} // where did I use this again?  I'd need to scroll
             | up.         );
             | 
             | versus                   var result = await query(
             | sql'SELECT * FROM foo.bar where bar = ${baz}
             | -- 100 more lines of where clauses, CTEs, etc.
             | `);
        
             | justeleblanc wrote:
             | I'd rather have the language settle on one single
             | templating syntax rather than every library and their son
             | bake a half-assed one. "Oh, does query use the : syntax?
             | The $ one? Does it take the template string first, or the
             | arguments?" And with your example, `query` needs to figure
             | out how to parse the string, extract the template slots,
             | and pass the correct arguments into the correct slots. It's
             | a recipe for disaster if every library needs to reimplement
             | that.
        
               | jmull wrote:
               | Well, people could settle on a common templating syntax
               | without making it a language feature. The fact that they
               | haven't tells you it's not that important, relative to
               | other concerns.
               | 
               | It's not like "figure out how to parse the string,
               | extract the template slots, and pass the correct
               | arguments into the correct slots" is rocket science.
               | 
               | And it's not like people are going to rewrite the
               | numerous existing libraries for this kind of thing. The
               | new tagged-template APIs are going transform their
               | arguments and call the existing APIs.
               | 
               | I guess it's nice that new Javascript-specific templating
               | languages can have common escaping syntax. It's just hard
               | to get excited about the 15th standard.
        
           | tofuahdude wrote:
           | Can confirm. This is the best use case I've come across. You
           | can dynamically compose queries and not even think about
           | argument positioning. No concern about injection. Better
           | performance than named variables that are translated into
           | positional.
        
         | [deleted]
        
         | frob wrote:
         | I find them to be really useful for simple and targeted tasks.
         | For example, simplur[1] for pluralizing strings and dedent[2]
         | just for developer ergonomics.
         | 
         | [1] https://www.npmjs.com/package/simplur
         | 
         | [2] https://github.com/dmnd/dedent
        
           | conaclos wrote:
           | Is there a difference between
           | dedent`something ${code}`
           | 
           | and                  dedent(`something ${code}`)
           | 
           | ? Not sure to understand the advantage of tagged strings
           | here...
        
       | Ezku wrote:
       | 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.
        
         | dayvid wrote:
         | The big hurdle is a lot of new jargon that sounds more
         | complicated than what it's doing.
        
         | klodolph wrote:
         | Agreed. My main complaint is that some of these changes don't
         | filter down fast enough for my liking, because I've bumped into
         | the issues they fix, often enough.
         | 
         | That, and for various reasons, it's easy to use "import"
         | everywhere in browser-side code, but painful to use "import" in
         | Node. That's a major selling point for ESBuild in my mind--I
         | can avoid dealing with Node as much.
        
         | myhf wrote:
         | Yeah, the language changes seem pretty minor and incremental. I
         | think the more interesting changes in the last few years have
         | been with engines. All major browsers now support ESM modules
         | and custom elements.
        
         | pjmlp wrote:
         | When I look at clever TypeScript, I always think the code was
         | written by either Haskell or C++ template metaprogramming
         | refugee, and this isn't good for the longevity of the language,
         | see what happened to Scala's adoption because of it.
        
           | quickthrower2 wrote:
           | Typescript will have no adoption problem. It is the defacto
           | only compile to js language supported in NPM. It is also
           | ergonomic to JS devs who want or are forced (at work) to use
           | typing and an option on most scaffolding tools like NextJS or
           | CRA. The fact that TS is actually very good just confounds
           | this more!
           | 
           | It will live as long ad JS is popular. The main threat is web
           | assembly which will make JS compatibility seem quaint.
        
           | whizzter wrote:
           | While I'm an C++ refugee, most of the "clever" TS stuff I
           | write is due to JS framework idioms creating duplicate
           | work(redux-reducer typings...) or forcing 'any' escape doors
           | to the degree TS use doesn't help. Doesn't mean I'm "above"
           | using any escape hatches where appropriate though or keeping
           | things "dumb" (most of my TS code is fairly monomorphic).
        
             | canadianfella wrote:
             | [dead]
        
           | yamtaddle wrote:
           | Yeah, this is why I wince every time TS gets another feature.
           | 
           | IMO it was entirely good enough for what it does _quite a
           | while_ ago. No need to add more--that 's purely introducing
           | risk (of the language's ecosystem getting worse, mainly) from
           | my perspective.
        
             | arnorhs wrote:
             | On the contrary, many of the new TS features over the last
             | year or more have been around making type inference smarter
             | and allowing for less explicit typing
        
         | HeavyFeather wrote:
         | Developers love hating on JavaScript, on change, and on
         | "complexification." This is all of the above.
         | 
         | The first comment I read after yours is literally _" I hate how
         | much programming languages change"_
        
         | parentheses wrote:
         | The way JS/TS change _feels_ a lot more haphazard.
         | 
         | For example why introduce a new method to support negative
         | indexing. Supporting `array[-1]` instead of `array.at(-1)`
         | would mean one less thing to remember.
         | 
         | Many of the changes make the language feel like a hodge podge
         | made from parts of other languages. This lack of cohesion is
         | IMO what makes upgrading the language always feel like moved
         | cheese.
        
           | connor4312 wrote:
           | Because your example is a breaking change, and breaking
           | changes are hard to make in a runtime that needs to
           | reasonably support two decades worth of web content.
           | 
           | For example, if you have a `binarySearch` function that
           | returns -1 if an element isn't found, a developer might do
           | something. `const result = arr[index]; if (result !==
           | undefined) { ... }`. This would then start returning the last
           | element instead of undefined at that index.
        
             | mhitza wrote:
             | We already have things like "use strict", because of
             | backwards compatibility. Following the same idea, we could
             | have something like "use ES2023" or something along those
             | lines. Issue with JavaScript is that browsers have in-flux
             | implementations of new features (as browser parent
             | companies see it fit for their usage), and there's no
             | cohesive point in time release process. I think "living"
             | standards, are part of the reason why the web stack is so
             | jumbled.
             | 
             | But what do I care, whatever mess and complexity arises
             | from these "good enough" implementations is left for the
             | generation after us to deal with :)
        
               | bobthepanda wrote:
               | In some sense, the messiness of the living standard is
               | also what enables large-scale web archival.
               | 
               | A lot of old code in other languages may be hard or
               | impossible to compile and run without significant work.
        
             | syg wrote:
             | Exactly right. `arr[-1]` means `arr["-1"]` and already does
             | something.
        
               | conaclos wrote:
               | It is also a breaking change to use new syntax and
               | functions since old browser does not support new
               | features. In this perspective `arr[-1]` seems a fair
               | breaking change.
        
               | zeven7 wrote:
               | No, because changing browsers to interpret `arr[-1]` as
               | `arr[arr.length - 1]` breaks existing sites that expect
               | `arr[-1]` to be interpreted as `arr['-1']`: That is, the
               | value stored on object `arr` at key name '-1'.
               | 
               | Changing browsers to interpret `arr.get(-1)` as
               | `arr[arr.length - 1]` doesn't affect any old code using
               | `arr[-1]`.
               | 
               | It's not about supporting old browsers. It's about
               | supporting old code.
        
             | RobotToaster wrote:
             | Why is there still no simple way of handling changes like
             | this?
             | 
             | Surely there should be a simple way to have a header in
             | each file with the language version, and then the file will
             | be interpreted as that version?
        
               | zeven7 wrote:
               | All of this was hashed out during the "Harmony"[1] days.
               | Versioned-JS was of course one possible future. Maybe
               | even still is. But the prevailing decision coming out
               | around that time and leading to ES5 and ES2015: We'll add
               | "use strict" as a single-point-in-time breaking opt-in
               | upgrade to fix a lot of the common problems, but let's
               | otherwise stick to "One JavaScript"[2].
               | 
               | You may find [2] and [3] especially enlightening to
               | understanding this thinking, and any other discussions
               | from ES Discuss on the topic if you fell like digging
               | into history.
               | 
               | [1] https://johnresig.com/blog/ecmascript-harmony/
               | 
               | [2] https://2ality.com/2014/12/one-javascript.html
               | 
               | [3] https://esdiscuss.org/topic/es6-doesn-t-need-opt-in
        
               | pavlov wrote:
               | Well, "use stricter" and "use strictest" are still
               | available...
        
               | KyeRussell wrote:
               | !important
        
               | RyanCavanaugh wrote:
               | _Maybe_ this is simple in implementation, but it 's
               | definitely not simple in developer experience.
               | 
               | You grab some code in one of your old projects for
               | implementing a binary search. Can you copy-paste it into
               | a new project that targets a newer language version?
               | 
               | The question isn't as simple as "does it have syntax
               | errors", because we're talking about changing semantics
               | here. Given a set of semantic changes and a piece of
               | code, figuring out (either as a human or a computer)
               | whether the observable characteristics of that code have
               | changed is somewhere between vexing and impossible. It's
               | entirely possible, for example, that your code encounters
               | changed semantics, but not in a way that changes the
               | actual behavior of the code.
               | 
               | In this world it just becomes very, very difficult to
               | reason about extremely common operations; it'd be a
               | constant source of frustration. There's a good reason you
               | rarely see languages versioning their _behavior_ in
               | impactful ways.
        
               | Garlef wrote:
               | > Why is there still no simple way of handling changes
               | like this?
               | 
               | This is nothing JS specific. Breaking changes are
               | breaking changes. If you can, don't introduce them.
               | 
               | > simple way to have a header in each file with the
               | language version
               | 
               | One special aspect that differentiates JS from other
               | languages:
               | 
               | It's both a language AND a universal runtime. A lot of JS
               | that's executed is not JS that's written by humans but
               | generated by a compiler/transpiler.
               | 
               | So adding a layer of header versioning is not a big win
               | in terms of developer experience: It would anyways be the
               | deployment toolchain that's responsible to deal with such
               | a versioning scheme. It would ideally be invisible to the
               | developer.
        
           | [deleted]
        
       | manv1 wrote:
       | "The only programming languages that people don't hate on are the
       | ones nobody uses." - someone online
       | 
       | Negative indexes might actually be useful.
       | 
       | At some point I actually need to read the actual language specs,
       | I guess.
        
         | manv1 wrote:
         | For reference, here's the current spec...all 833(!) pages of
         | it.
         | 
         | https://www.ecma-international.org/publications-and-standard...
        
         | goatlover wrote:
         | The author of C++, so maybe take that with a little grain of
         | salt.
        
           | calvinmorrison wrote:
           | C++: an octopus made by nailing extra legs onto a dog. --
           | Steve Taylor
           | 
           | But more seriously, languages that are less formally made and
           | have grown organically all deal with these types of things.
           | PHP is a great example of a language with a TERRIBLE core
           | library filled with numerous "don't use this" and "yes this
           | doesn't make sense" and esoteric foot guns.
           | 
           | Of course, these languages are the ones that took off and
           | people use everywhere. And languages like PHP have made great
           | strides to the point that using PHP8 with a modern set of
           | libraries is not so bad.
        
             | goatlover wrote:
             | Yes, but Go is also popular and famously resists doing that
             | as much as possible. Maybe language popularity isn't a good
             | metric, since there could be other reasons a language
             | becomes popular. Worse is better, and what not.
        
       ___________________________________________________________________
       (page generated 2023-03-09 23:00 UTC)