Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Design Meeting Notes, 5/10/2023 #54228

Closed
DanielRosenwasser opened this issue May 12, 2023 · 8 comments
Closed

Design Meeting Notes, 5/10/2023 #54228

DanielRosenwasser opened this issue May 12, 2023 · 8 comments
Labels
Design Notes Notes from our design meetings

Comments

@DanielRosenwasser
Copy link
Member

Transformer Plugins

  • Concept in the TypeScript API called customTransformers
    • You can provide transformers before and after for JS output files, and after declaration files.
  • Can we support this via the tsc command?
  • We released 5.0 recently, but it broke a lot of how people do patching.
  • Main reason people do patching (Yarn aside) is doing custom output transformers.
  • These transformers pass in the Program - are they effectively doing type-directed emit?
    • Is type-directed emit a bad thing?
    • You need an EmitResolver for something like runtime type-checks, or minification, or whatever.
    • [[Discussion on philosophy of "statically analyzable" emit vs. "type-directed" emit]]
    • Some of why type-directed emit is "bad" is because we don't have the full program.
    • Another is that we're not sound.
  • TypeScript itself had to avoid type-directed emit due to these factors and out of trust - when you write JavaScript in TypeScript what you get is what you see!
    • But when you use a plugin, the problems are
      • They might be slow.
      • They might do the wrong thing, often because of unsoundness.
        • And when that happens, people may kvetch and we have to say "yeah we know, we said that you".
  • If we're doing watch plugins, it feels like transformer plugins.
    • And then module resolution plugins?
      • 😬
  • customTransforms have existed for over 5 years, always been an asymmetry (if not just annoying) that you have to use a bundler or write a wrapper for tsc.
  • Feels like the safest plugins to most dangerous are transforms, watch, and module resolution.
    • Some feel the opposite.
    • Why?
      • Transforms are fairly linear. Watchers can bork state of the program, module resolution leads to an incorrect program, and most people don't know the real scope of what you need to support resolution correctly.
      • Other reasons: resolutions from Deno, Yarn, etc. would not fit into most resolution strategies.
  • Proposal:
    • Build on the plugins array.
    • type is a new field for each plugin entry.
      • Maybe transform plugins get "type": "transform" or whatever.
      • Maybe Watch plugins get "type": "watch"
      • Try not to conflict with ts-patch or others who currently use plugins
    • First step - allow users to provide customTransformers.
    • All of this on the command line requires some new --allowPlugins flag.
  • Come back to this at next meeting.

Type Argument Placeholders and Feedback

#26349

  • Changing overload resolution broke a ton, so we backed off of the "partial type argument" thing.
  • Lots of people watching Implement partial type argument inference using the _ sigil #26349 - but all with different needs.
  • People saying "I have a type argument that never should be specified"
    • Translates to "We need an existential at this location"
  • People really don't want users to write foo<SomeType, _, _, _> even if it's an improvement from foo<SomeType, VeryLongType, VeryLongType, VeryLongType>
    • Flow has existentials, Rust has impl trait types, etc.
    • But existentials act as something that adds quite a bit of work to every call.
    • Also, not full agreement here that everyone on the issue is looking for this feature.
  • preferinfer?
    • Using type argument defaults means that we fall back to the default itself if it's not specified - so preferinfer says "no no no, the default isn't desirable. You want this thing to be optional, but to use inference as a fallback if it's not specified".
      • That's almost always the behavior you want.
    • New type param modifier to allow for partial inference based on signature declaration #53999
    • Switches internal compiler behavior, but doesn't have a strong type theoretic foundation.
  • Feels like people want a local type alias.
    • But type alias wouldn't provide inference sites.
  • We don't feel great about preferinfer at this moment - it feels like the scope is narrow.
@DanielRosenwasser DanielRosenwasser added the Design Notes Notes from our design meetings label May 12, 2023
@Andarist
Copy link
Contributor

People really don't want users to write foo<SomeType, _, _, _> even if it's an improvement from foo<SomeType, VeryLongType, VeryLongType, VeryLongType>

i wouldnt say that - i think that many in the PR comments welcome this improvement. It’s just that many think (myself included) that for certain use cases it feels like a needless requirement put on the final consumer of the API. Some APIs are just designed in a way that would require this at call site - and at that point, why not allow it somehow to be the default behavior of the signature?

If i have to say to all of my users “u need to use _ as a type arg every time u call this function” then I will say that to them. It’s just that i would prefer it if i wouldnt have to because its one more thing they have to remember when interacting with my code

@ssalbdivad
Copy link

Just wanted to reiterate that as @Andarist suggests, I am a big proponent of incremental progress so long as there is a consensus around how it could eventually fit in to a full solution👍

@fatcerberus
Copy link

People really don't want users to write foo<SomeType, _, _, _> even if it's an improvement from foo<SomeType, VeryLongType, VeryLongType, VeryLongType>

If i have to say to all of my users “u need to use _ as a type arg every time u call this function” then I will say that to them. It’s just that i would prefer it if i wouldnt have to because its one more thing they have to remember when interacting with my code

I think these two passages are effectively saying the same thing. i.e. "Yeah, it's an improvement, but I'd really prefer if there was a better way..."

I am a big proponent of incremental progress so long as there is a consensus around how it could eventually fit in to a full solution

I suspect this is exactly the reason for the caution here - if said incremental progress involves a new feature, then the way to use that feature now has to then be maintained for backward compatibility even if a different, better way comes along later--and now you have multiple ways to do the same thing (even though one of the ways is effectively legacy baggage) and people get into unproductive style wars over it. So I'm only for incremental progress if what's implemented now is a proper subset of what all will eventually be implemented.

@fatcerberus
Copy link

fatcerberus commented May 13, 2023

Switches internal compiler behavior, but doesn't have a strong type theoretic foundation.

I'm quite amused by this because it reminds me of when people write unsound generic functions/classes and then get confused when the compiler yells at them. The compiler knows the function isn't safe but the coder doesn't realize that because they're only thinking of cases where the type parameter gets inferred. There's no type theoretical basis for that kind of thinking (a type parameter implies universal quantification), but that's what ends up happening simply because TypeScript's design makes explicit type arguments an antipattern.

@Andarist
Copy link
Contributor

Andarist commented May 13, 2023

I think these two passages are effectively saying the same thing. i.e. "Yeah, it's an improvement, but I'd really prefer if there was a better way..."

Maybe i misread the design notes late in the night - it read to me a little bit as if we were not recognizing _ being an improvement. So I wanted to assure the team here that it's definitely an improvement already but we just wish for some further improvements for our use cases. It feels that _ is definitely in the right direction because it doesn't preclude further improvements - so whatever we land on (if anything) to address our concerns shouldn't really clash anyhow with _ (it would still be helpful for other use cases).

@RyanCavanaugh
Copy link
Member

I suspect this is exactly the reason for the caution here - if said incremental progress involves a new feature, then the way to use that feature now has to then be maintained for backward compatibility even if a different, better way comes along later

I would just echo this 100 times over, because the entire reason we're in a difficult spot here in the first place is that generic defaults were sort of rushed in, when we should have really done partial inference for unspecified type parameters instead. it's significantly easier to do the right version of a feature first than to do the OK version and then a better version later.

@jakebailey
Copy link
Member

I wrapped up the transformer stuff into a concrete-ish issue on #54276.

@ssalbdivad
Copy link

so long as there is a consensus around how it could eventually fit in to a full solution

In light of what @RyanCavanaugh and @fatcerberus mentioned, I think a more concrete way to say this would've been that I think that a final decision should be made on syntax for both call-site and declaration-site inferred parameters before either is added to the language.

That said, I do think we have a few promising options for each, so I do hope to see one of them in a nightly build in the not too distant future🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Design Notes Notes from our design meetings
Projects
None yet
Development

No branches or pull requests

6 participants