[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)