Description
Binding Pattern Breaking Changes
-
Motivation
declare function g<T>(): T; // Type is { x: any, y: any, g: any } // which is kind of dumb. const { x, y, z } = g();
-
Other more complex issues.
-
Why?
-
Best thing we can imagine is left-to-right completions for
const { x, y, z } = { /*|*/ } // ^ // We expect completions for x, y, z.
-
-
Current proposal is to disable for object binding patterns, but re-enable contextual typing from array binding patterns.
-
We still don't fully understand the inferences - probably best to do that.
-
When we started doing implied types from binding patterns, we didn't have types apart from
any
- now havenever
andunknown
. -
Let's do a full revert and think through this a bit more.
Node ESM Support
#44501
weswigham#67
weswigham#68
-
New resolution modes:
node12
andnodenext
-
CJS and ESM files can resolve files via different paths based on the syntax and containing file.
// Always follow CJS resolution import foo = require("foo") // Dynamic import - always follow ESM resolution const a = import("foo"); // Always depends on the **containing file**! import * as a from "foo";
-
This is "solved" albeit complicated, but what is not solved is...
-
Import type syntax:
type Foo = import("foo").Foo;
- Can't disallow in CJS files because of existing CJS
.d.ts
files.
- Can't disallow in CJS files because of existing CJS
-
So how do you differentiate between "this should resolve as ESM vs CJS"?
- Don't have any other syntax for inline type import syntax.
-
Could have a different conditions passed into
import(...)
types.- Like in an import assertion:
import("foo", { /*conditions*/ })
- Like in an import assertion:
-
Why does this matter?
- Different resolution will fetch you a different file
- Even if both are to the same package path.
- e.g.
import "lodash"
andrequire("lodash")
can fetch TWO DIFFERENT FILES innode_modules/lodash/
.
- https://nodejs.org/api/packages.html#packages_conditional_exports
- Different resolution will fetch you a different file
-
Technically the MVP doesn't need to include this...but it will likely be an issue.
-
If you need to reference a type in ESM, either in
.d.ts
emit or by-hand, can you just writeimport "esm-file";
- No, you can't :(
-
Can you lean on
import()
types always getting inferred from containing context?- Yes, you have to for compat, but you can't model a CJS file that actually
import()
s an ESM.
- Yes, you have to for compat, but you can't model a CJS file that actually
-
Import assertions affecting module resolution?
-
Seems like a no-no, but might need to use sibling conditions as a way to bypass that.
type Foo = import("foo", { assert: { }, resolver: "esm" });
-
-
Heavy regret of not introducing
require()
types; now you need a "realimport
type" type. -
Whole thing is such a 🤬😫😢😭
-
What if we just didn't let you write
import
in a non-module file?- Force users to write
require()
in CJS - Goes against a lot of expectations.
- Isn't that what people want to write though?
- What is the guidance? Users should use
module: node12
, but as far as they're concerned they're still doing CJS.
- Force users to write
-
If our heads are spinning from this, users' will too.
- A lot of concerns around complexity.
-
Stripping out complexity?
- Export maps are complicated, but are a necessary feature for bridging the ESM and CJS worlds.
- Trying to get it set up is rocket science, not supporting it would be worse.
- Export maps are complicated, but are a necessary feature for bridging the ESM and CJS worlds.
-
"maybe I'm just old and grumpy"
- "no this sucks"
-
We should be able to explain the happy path to people.
-
We have a lot of concern over how easily we'll be able to communicate best practices here; this is not just something that can affect TypeScript, the complexity can significantly hurt Node.js too.