Repository: TypeScript
Issue: Design Meeting Notes, 5/7/2024
Labels: Design Notes


# TypeScript as ESM (one day!)

* https://github.com/nodejs/node/pull/51977 fixes the ESM/CJS schism in the Node.js ecosystem.
* The restriction of this work is that if you `require("some-esm-module")`, and that hits a top-level `await`, then it fails.
    * Most modules don't.
* What would this look like in TypeScript?
    * Hit some issues - TypeScript does some conditional `require()`s.
    * But the only way to do a conditional `import` is with dynamic `import()` and a top-level `await`.
    * Explored this with some folks from Bloomberg and Igalia, reached out to the modules harmony group.
    * One proposal (https://github.com/nodejs/node/issues/52599) was a function to do synchronous `import` in any module.
    * Related PR: https://github.com/nodejs/node/pull/51977 introduces `process.getBuiltinModule(id)`.
* Have an example version of Node which just turns the new `--experimental...` flag, patches the global `process` object to basically polyfill in `getBuiltinModule`.
    * And it works!
* There's also an idea for `import.now` (synchronous `import`).
* Also ideas for `weak`/`optional` imports - might be attributes on the import.
* Do we actually need that `getBuiltInModule` function?
    * You can use `import` conditions.
    * Can you also just create a `.cjs` module exports `require` or something similar?
    * Another idea: ship ESM, have different API entry-points.
    * We can play with all these...
    * But you really want people to be able to create a single file to make things convenient (or have a continuous ESM module graph at the least)
* Why is ESM good?
    * Allows us to split shared parts of the TypeScript package without incurring a performance penalty.
    * Also, people can't tree-shake as well against us - static analysis can only go so far.
    * Also lets us use ESM utilities more seamlessly.
* What's the timeline on this?
    * Feels like the Node devs (and ecosystem) are really excited about `require(ESM)`
        * It is worth asking: could `require(ESM)` be backported to Node 20?
    * TypeScript currently supports Node 14...
        * We could evaluate our policy on this.
    * So it all depends on us and on Node as well.
        * How far back it gets backported (if at all).
        * How soon we're willing to jump our minimum supported Node version.

# Add `BuiltinIteratorReturn` type (part of adding `TReturn`/`TNext` to `IterableIterator`)

https://github.com/microsoft/TypeScript/pull/58243

* Trying to thread `TReturn`/`TNext` through the `IterableIterator` type.
* Last time we talked about `TypeScriptSettings` https://github.com/microsoft/TypeScript/issues/58429
    * Mixed reception.
* Now discussing `BuiltinIteratorReturn` intrinsic type alias.
    * Toggled by *some* compiler option.
    * In PR, it's toggled by `--noUncheckedIndexedAccess`.
* Basically `BuiltinIteratorReturn` is `undefined` or `any` depending on the option.
* The built-ins have to explicitly thread through the `BuiltinIteratorReturn`.
* Why isn't `BuiltinIteratorReturn` used as the default type argument for `IterableIterator` etc.?
    * Because the built-ins specifically have known types, but these types are used as protocols that need to be more general.
* It's weird to put it under `--noUncheckedIndexedAccess`. We get it, but it would be confusing.
* Is there a reason for us not to mkae the behavior the default?
    * If you write
    
      ```ts
      if (someMap.has(someKey)) {
        someMap.get(someKey)!.method()
      }
      ```
      
      you get an error if you don't provide that postfix `!`.
    * Why special-case here?
        * There are places where you know "I know this iterator has at least one value".
        * But the same applies with `Map`s.
        * Also, this means everyone using built-in iterators now has to think about this (including the DOM types).
* Before, the behavior was you got `any`
* All of this feels like a strictness tightening.
    * Seeing less `any` - `noImplicitAny`?
    * Hitting a possible `undefined` - `strictNullChecks`?
    * Leverage the symmetry of `noUncheckedIndexedAccess`?
    * Or just introduce a new flag like `noUncheckedIteratorResults`?
* We'd probably want to do something similar for `catch` variables as well.
* Will probably bikeshed where the new behavior lives under.