-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
Consider redesigning "resolution-mode" to not be an assertion since it's not an assertion #48644
Comments
We repurpose object literal syntax in type space to represent object literal types, I don't see why repurposing assertion syntax in type space for representing options for resolution is meaningfully different. No effect on the runtime, completely separated from any runtime guarantees, and on the surface level, looks and behaves exactly like assertions do (as a kind of option bag for the import). |
In the first case you are repurposing curly braces and other punctuation, in the second you are abusing the function assertResolutionRequire(importDecl) {
importDecl.resolution = "require";
}
No, if you were to rewrite some assertion you expect that the only change in outcome should be the pass or failure of that assertion. It is confusing and dangerous for other semantics to change while the word And again it's not like there was ever some radical advantage of this syntax.
This is a misconception to shift away from. Import assertions are not meant to be an options bag. |
Yes,
There is! The AST nodes are the same as the non-type versions of the call, so tools like
I think that's an argument that may hold water with engine authors willing to argue implementation minutiae, but is a tough sell in general to the average user. Heck, the syntactic differences between import alias |
fyi: i started writing this comment an hour ago, so i have not incorporated comments posted in the last hour ago :-)
I think this is where the misunderstanding is coming from. Import assertions are NOT options bags for imports. Let me elaborate: In ES, building of the module graph (often referred to as module loading) can be thought of as three distinct stages: resolution, asset loading, and asset evaluation.
Specification background / sourcesThe ECMA262 combines all of these three steps into a single The split of steps as described above is enforced in the spec anyway though the following normative requirement on implementations of
Import assertions slot into this by adding three more steps:
Specification background / sourcesAs mentioned earlier, ECMA262 combines all of these steps into a single host AO The import assertions proposal also adds a new requirement to the host AO though:
This new requirement enforces the separation between step 1 and step 2, and between step 3 and step 4. The confusion stems around it looking like that the assertion tells an engine how a given module is to be evaluated. This is NOT the case though. For web browsers / Deno (which use the module loading algorithms from the HTML spec) for example, when a user performs a JSON import ( So now with the spec details out of the way, back to the problem at hand: TypeScript uses the assertion to modify how resolution is performed. This is a violation of the ECMA262 spec. If that in itself is "bad" is dependant on if you think TypeScript should adhere to the spec closely or not, but that is not my concern right now. What I do think is really concerning is that TypeScript is setting the precedent that an assertion on a statement that for all intents an purposes looks to the average Joe like an ES
Thank you for your consideration. |
To elaborate some more on my above comment:
I think this is really critical. Users need to understand that |
Can we avoid making statements like this? So I would rather have us focus on
|
I don't think this is a similar comparison. Object literal types exists in the type domain in a non-analogous to JS position whereas this new
I'm wondering about the issue with a comment directive or only allowing something like export type LocalType = require("pkg").RequireInterface
I think Luca was just making the point that import assertions aren't an options bag. |
Yeah, sorry, I tried to elaborate on this in the sentence following that one. It kind of depends on if you consider
I can comment on this. This will to some extent be an issue for Deno, yes. Our general purpose module resolution system that we use for both the Deno runtime, bundling, and static analysis tools like It also requires more mental overhead for users when parsing |
Don't you need to pass something extra in anyway if there's a new syntactic construct or a leading comment? |
I might be misunderstanding, but I don't see why there would need to be a new syntactic construct or leading comment. Doesn't @dsherret's suggestion have the same effect as the new feature, but in existing syntax? |
Semantic comments are pretty much a nonstarter for meaningful type syntax - comments that aren't |
How do you handle detecting the mode of a node-style import in your node compat codepath? (Eg, if it's a |
In node, they're already not. They depend on the nearest context |
@weswigham thanks for the clarification on the
I see, because
I don't agree this is a needless distinction since For a possible alternative keyword, I kind of like import type { TypeFromRequire } from "pkg" with {
"resolution-mode": "require"
};
export type LocalType =
& import("pkg", { with: {"resolution-mode": "require"} }).RequireInterface |
|
Sure, but nothing in an It's already the case that you can write things in TypeScript-only positions that use the same syntax as JavaScript keywords but have different semantics:
So for the TypeScript-specific construct |
I think they key is that with |
From a user perspective blocking the import entirely and modifying it are both just different flavors of modification - the distinction is artificial. |
Let's say that we added this to the documentation
As a TS-only declaration, we're allowed to specify the semantics of what |
Well a violation would occur if a user has imports with different resolution modes specified for the same resolved specifier. So if that is explicitly forbidden, it seems like a possible resolution to the issue. I'm telling you... import assertions were a mistake :( |
Some key points I want to touch on from #48644 (comment):
1 - It's not moot because it's in types, the consequences of rewriting such an "assertion" still has the confusing impact I mentioned in #48644 (comment). 2 - I think a normal outlook here is that if you have a new feature, and that feature might need a new syntax, there's an existing syntax you're eyeing but it has a big incompatibility, you just have to add the new syntax. That's sort of what comprises a language in the first place, right? When JS inevitably has actual import modifiers, we know they're not going to shoehorn it into 3 - I think this is adapting to user expectations in a way that exacerbates their cause for confusion in the long term. Adopting a syntax from JS and twisting its meaning in this manner seems like one of the worser things TS can do for the JS ecosystem. I guess technically that design goal only pertains to transpiled code...
Well that's not the user understanding you're trying to build on most importantly, not the implementation and not even going to be written in the doc outside of the hypothetical. What's conceptually sensible about it? |
And this is key flaw in your assumption: this is totally incompatible with node resolution (at least when you're like us and interpret imports as both cjs and esm in the same compilation!) and has to be conceeded so long as, like us, you unify cjs and esm resolvers into a single system rather than splintering it like node itself does. (Which has the same appearance, ultimately.) Our compilation model has all imports as under a single resolver that acknowledges source location and context - in some senses, it's much more robust than what's specified, by necessity. Put simply: In node the specifier |
Oh, absolutely, terrible idea, but the syntax is there for the using now 😂 |
@weswigham @DanielRosenwasser @RyanCavanaugh thanks for your points and engaging this thread. Reading through the recently linked design meeting notes has also been more enlightening and thanks for outlining all the other ideas you had. I can't think of any more suggestions... |
Closing due to #49055. Thanks! |
Suggestion
The latest TS 4.7 has a new "resolution-mode" feature (https://devblogs.microsoft.com/typescript/announcing-typescript-4-7-beta/#resolution-mode) that can be used to select which module resolution to use:
I understand this is "ok" by the spec police because it appears in an
import type
, but this is not an assertion so it appearing in an assert clause doesn't seem ideal.Note: I say this is not an assertion because import assertions assert something about the module. This instead seems to be a module resolution directive... maybe I'm mistaken though.
🔍 Search Terms
resolution-mode import assertions
⭐ Suggestion
I think @nayeemrmn's suggestion for using a comment directive seems more ideal #47807 (comment):
...but that's not as conveinent when used in a type like shown in the example:
Perhaps this should be?
Or, perhaps still using a comment directive:
The text was updated successfully, but these errors were encountered: