[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)
 
web link (medium.com)
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;
  | 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`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 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
    | 
    | 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>
    | 
    | 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)