1

Ten Years of TypeScript mentioned "It’s actually surprising how well the design goals for TypeScript have held up."

I am particularly interested in this goal, ""Avoid adding expression-level syntax.", for example someone mentioned here TypeScript Features to Avoid

This basically comes down to: avoid TypeScript features that clash with TypeScript's design goals. Specifically, the one to: Avoid adding expression-level syntax.

So is there any specific example of expression-level syntax that ts may have added but because of the design goal it didn't ?

I think optional chaining was added to TS first before it was added to JS, e.g node14 supports optional chaining at least 1 year later than ts supports it. Correct me if I was wrong.

I feel template literal string type ts introduced in 4.1 for combining Union string literal types seems to be another example of introducing expression-level syntax whose semantics is different from js.

Qiulang
  • 10,295
  • 11
  • 80
  • 129
  • 1
    Does [ms/TS#1579](https://github.com/microsoft/TypeScript/issues/1579) count as a specific example for your purposes? It's a proposal to add `nameof x` that compiles to a string. It's currently closed as "Waiting For TC39" because the policy is that any new expression level syntax should come from JS first. It's hard to name proposed syntaxes that were both seriously considered for TS *and* didn't end up being proposed as JS. – jcalz Oct 13 '22 at 16:16
  • @jcalz Yes that is a good example. One of the reasons I asked is because I think optional chaining was added to TS first long before it was added to JS – Qiulang Oct 14 '22 at 02:45
  • 1
    Optional chaining in TS was implemented in [ms/TS#33294](//github.com/microsoft/TypeScript/pull/33294) and released with [TypeScript 3.7](//www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining). This was *after* [the TC39 proposal](//github.com/tc39/proposal-optional-chaining) reached Stage 3 of [the TC39 process](//tc39.es/process-document/). Stage 3 is when you expect JS engines to start implementing features if they haven't already. So optional chaining is still a feature that was added to TS *after* it was essentially certain that JS would support it. – jcalz Oct 14 '22 at 02:51
  • One of the goals of TS is to give people access to JS features that their favorite JS environment might not yet support, via downleveling. But that doesn't really count as *adding* expression-level syntax, so much as *supporting* existing syntax. – jcalz Oct 14 '22 at 02:53
  • So I can write up an answer mentioning https://github.com/microsoft/TypeScript/issues/1579 because it's an unambiguous example of a possible TS feature that would have needed JS syntax and was never (at least so far) adopted by JS so it never made into TS. I'll do it when I get a chance – jcalz Oct 14 '22 at 02:58
  • @jcalz Yes please write an answer for that! You also explained Optional chaining very well because I know nodejs 14 added it in 2021, so I had thought ts added it first. – Qiulang Oct 14 '22 at 03:11

2 Answers2

3

There are certainly situations where TypeScript has waited to add expression-level syntax until it was clear that JavaScript would almost certainly support this. The current threshold for this is when an ECMAScript proposal reaches Stage 3 of the TC39 Process.

Because TypeScript allows you to target a particular version of ECMAScript when you build, this often means that such new features will be downleveled if your targeted version doesn't support the feature. This may end up looking like TypeScript has added expression-level syntax, since the feature shows up in TypeScript earlier than whatever runtime engine you're using. But it's not really doing so.

Features like optional chaining and nullish coalescing are evidence that TypeScript did not add expression-level syntax, since the order of operations was something like

  • someone suggests a feature in TS that would require expression level syntax... e.g., "safe navigation" operator, microsoft/TypeScript#16, now known as optional chaining.

  • this is not implemented in TS... e.g., this comment in ms/TS#16.

  • instead, it is created as a Stage 0 TC39 proposal. This proposal makes it to Stage 1, then Stage 2, then Stage 3 of the TC39 Process

  • at this point it is implemented in TypeScript, see microsoft/TypeScript#33294.

  • for a brief time this is technically expression-level syntax added to TypeScript before it is part of the actual ECMAScript spec

  • the proposal makes it to Stage 4

  • it is included in the next ECMAScript language specification, see ES2020.


If that's still too ambiguous, then we should find examples of proposed TypeScript features that would have required expression-level syntax, but which were rejected, and have, at least so far, stayed rejected because the feature was either never proposed to TC39 or the proposal has, at least so far, not reached Stage 3.

One such feature is microsoft/TypeScript#1579, the proposed nameof operator, which would evaluate an expression to a string version of itself, possibly as requested here. So const a = 5; console.log(nameof(a)) presumably prints "a".

This was never implemented. The request was eventually marked as Waiting for TC39 and eventually the GitHub issue was locked.


So there you go. Note that there are examples of expression-level syntax features added to TypeScript and then not added to JavaScript, or where the JavaScript version changed significantly enough from the proposal that the TypeScript work had to be undone or changed, with much headaches all around. I'm not going to go too much into this, but I'll just list some here:

Never or not yet part of JS: enums; protected class fields; private class fields; parameter proprties; namespaces.

Part of JS or soon to be part of JS but where the TS implementation does not conform to the spec and has been or will need to be fixed: public class fields; decorators.

jcalz
  • 264,269
  • 27
  • 359
  • 360
  • I feel [template literal types](https://devblogs.microsoft.com/typescript/announcing-typescript-4-1/#template-literal-types) introduces in 4.1 is an expression-level syntax that would surprise js deveoper because the use of `|` is different from js for its usage of combination. – Qiulang Oct 18 '22 at 06:53
  • It’s not expression-level; it is purely part of the type system. And the union operator is also not expression level and has nothing to do with template literal types per se. I’m very confused. – jcalz Oct 18 '22 at 11:44
  • Oh sorry I mean '|' is a express level operator, no ? – Qiulang Oct 18 '22 at 12:03
  • 1
    No, not when used in a type context. Expression level is code that would not be simply erased when compiled to JS. The union operator is written like the expression level bitwise OR operator but they are not the same. – jcalz Oct 18 '22 at 12:09
  • So it is like `typeof` used in type context. TS "reuses" typeof operator in js. I always mix up "avoid adding expression-level syntax" with "adding new function to an old operator". – Qiulang Oct 19 '22 at 09:06
1

The nullish coalescing operator ?? and optional chaining operator ?. could easily have been added to TypeScript and compiled down to a ternary conditional ... ? ... : ... in JavaScript, but weren't added at first.

Only when they were added to the ECMAScript standard did TypeScript start supporting them too.

Thomas
  • 174,939
  • 50
  • 355
  • 478
  • The optional chaining operator was exactly the reason I asked my question in the first place, I think it was added to ts first long before it was added to js standard. – Qiulang Oct 14 '22 at 02:48