4 ms·
The syntax from the perspective of type stripping has been relatively stable for more versions of Typescript than it was unstable. You had to reach all the way
by WorldMaker 2y ago
The syntax from the perspective of type stripping has been relatively stable for more versions of Typescript than it was unstable. You had to reach all the way back to 1.5 in part because it's been very stable since about 2.x. The last major shift in syntax was probably Conditional Types in 2.8 adding the ternary if operator in type positions. (The type model if you were to try to typecheck rather than just type-strip has changed a lot since 2.x, but syntax has been generally stable. That's where most of Typescript's innovation has been in the type model/type inferencing rather than in syntax.)
It's still just (early in the process) Stage 1, but the majority of Typescript's type syntax, for the purposes of type stripping (not type checking), is attempting to be somewhat standardized: https://github.com/tc39/proposal-type-annotations https://github.com/tc39/proposal-type-annotations
- teaearlgraycold 2y agoThey did just add a new keyword, satisfies, in 5.4. That would be a breaking change if you can’t upgrade the type stripper separately.
- panzi 2y agoBut at least its a loud failure and not a silent different interpretation of the source as the example was. Still.
- felixfbecker 2y agoThis is true, but in other cases they added keywords in ways that could work with type stripping. For example, the `as` keyword for casts has existed for a long time, and type stripping could strip everything after the `as` keyword with a minimal grammar. When TypeScript added const declarations, they added it as `as const` so a type stripping could have still worked depending on how loosely it is implemented. I think there is a world where type stripping exists (which the TS team has been in favor of) and the TS team might consider how it affects type stripping in future language design. For example, the `satisfies` keyword could have also been added by piggy-backing on the `as` keyword, like: const foo = { bar: 1 } as subtype of Foo (I think not using `as` is a better fit semantically but this could be a trade-off to make for better type stripping backwards compatibility)
- Timon3 2y agoI don't know a lot about parser theory, and would love to learn more about ways to make parsing resilient in cases like this one. Simple cases like "ignore rest of line" make sense to me, but I'm unsure about "adversarial" examples (in the sense that they are meant to beat simple heuristics). Would you mind explaining how e.g. your `as` stripping could work for one specific adversarial example? function foo<T>() { return bar( null as unknown as T extends boolean ? true /* ): */ : (T extends string ? "string" : false ) ) } function bar(value: any): void {} Any solution I can come up with suffers from at least one of these issues: - "ignore rest of line" will either fail or lead to incorrect results - "find matching parenthesis" would have to parse comments inside types (probably doable, but could break with future TS additions) - "try finding end of non-JS code" will inevitably trip up in some situations, and can get very expensive I'd love a rough outline or links/pointers, if you can find the time! [0] TS Playground link: https://www.typescriptlang.org/play/?#code/AQ4MwVwOwYwFwJYHsriUgPAFQHwAoBKYAbwChQLgAnAUzgitQCMBDKvcyrqCAG1+AsAzsGgBrKEgDuqYcCzAaADzg0oAExFN0vGiyicuFAPzA4VCDWAB6AFTACALmC3rhoyGd4Fy1RpFC5ghQAObuHibAAESBVMEhUeERnuAsvEI0SVwEWZQ5FAC+pO6QsIgowKzsAG5pls76AJ5OwNVICOokRUA https://www.typescriptlang.org/play/?#code/AQ4MwVwOwYwFwJYHs...
- WorldMaker 2y agoMost parsers don't actually work with "lines" as a unit, those are for user-formatting. Generally the sort of building blocks you are looking for are more along the lines of "until end of expression" or "until end of statement". What defines an "expression" or a "statement" can be very complex depending on the parser and the language you are trying to parse. In JS, because it is a fun example, "end of statement" is defined in large part by Automatic Semicolon Insertion (ASI), whether or not semicolons even exist in the source input. (Even if you use semicolons regularly in JS, JS will still insert its own semicolons. Semicolons don't protect you from ASI.) ASI is also a useful example because it is an ancient example of a language design intentionally trying to be resilient. Some older JS parsers even would ignore bad statements and continue on the next statement based on ASI determined statement break. We generally like our JS to be much more strict than that today, but early JS was originally built to be a resilient language in some interesting ways. One place to dive into that directly (in the middle of a deeper context of JS parser theory): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#automatic_semicolon_insertion https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...