-
Notifications
You must be signed in to change notification settings - Fork 12.5k
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
Ambient Module Declarations for Import Attributes (formerly known as Import Assertions) #46135
Comments
Thanks for opening this @sodatea! I think the important point with import assertions is that for the standard assertions ( So for native module types it only makes sense to declare ambient modules by assertion, never by name. |
Just wanted to mention that this would also be a boon for stuff like imagetools which provide complex types currently via query params, but could potentially use assertions instead (and have much better syntax and types as a result!) |
Thoughts on this, following discussion in #56359 Import attributes are a great way to tell a bundler how to interpret/preprocess a file being imported. Eg "load this as plain text", "load this as an ImageBitmap", "bundle this file and give me a URL to it". The same file may be imported using different types: import anImage from './icon.png' with { type: 'rollup-ImageBitmap' };
import aURL from './icon.png' with { type: 'rollup-bundled-url' };
import aBase64URL from './icon.png' with { type: 'rollup-base64-url' }; This is much better than the current pattern bundlers/TypeScript uses, where anything ending Some types, such as In a case like: import aDictionary from './styles.css' with { type: 'rollup-css-module' };
import source from './styles.css' with { type: 'rollup-text' }; The build tool may wish to create a definition file specific for I don't mind how the use-cases are solved, but here are some loosely-held thoughts/ideas. I know there are two types of
Taking from #56359, I assume this syntax is for ambient definition files: declare module "*" with { type: "css" } {
declare const _default: CSSStyleSheet;
export default _default;
} Open question, would it be valid to use types in the above? For example: declare module "*" with { type: "css" | "scss" } {
declare const _default: CSSStyleSheet;
export default _default;
} And I assume this syntax is for use in sidecar definition files: declare with { type: "css" } {
export const header: string;
export const footer: string;
export const button: string;
} It feels like exports outside one of these blocks should only apply to imports without attributes. I know this is hand-wavy and incomplete, but the process of picking a definition for an import with attributes could be something like:
|
For non-ambient declarations I think we'll also need a way to specify that there's no support for an import with no type attribute, as is true for CSS and JSON. |
|
I'd just like to point out that "sidecar" vs. "ambient" |
#56359 has a number of questions from the design meeting on this issue. I'll attempt to give my personal responses on them here to keep things collocated: Declaring modules with attributes
π (even though this wasn't a question) Allowing module declarations to key off of import attributes is in general a great feature that will work with all kinds of tool-specific attributes. I'd assume that lib.dom.d.ts would include a declaration like the above. Handling multiple matching module declarations
Presumably there can already be multiple matching module declarations with path wildcards. How does that work today? Merging? For CSS and JSON, I think there are likely three common cases where merging might happen:
Are import attributed even needed for module declarations?
The bundler vs browser issue is one reason, but I hesitate to call one behavior "bundler" because there are now bundler plugins that support the standard behavior. The real core reason is that import attributes are the way that browsers determine/verify the module type - they don't do so based on file name - so the type system should work the same way.
You absolutely do want the files to be resolved on disk. One of the problems with today's wildcard declarations is that jump-to-definition goes to the declaration and not the file. That might be useful sometimes when trying to debug your types, but usually you want to open the .css or .json file in your editor. Path-less declarations
Seems fine, though is this really different than Resolution
No. At least for the standard module types (json and css) the specifier should resolve exactly the same as without a type attribute. Those files might not be in the same root tree as the .ts files, but this can be handled with multiple root dirs. Even better, .json and .css files should be emitted if they are in the root dir and references as an import. There could conceivably be tools that alter specifiers of imports with certain attributes. Those will just have to use their own declarations? Emit
I think these files are part of the source tree and should be copied over. Projects shouldn't need to add extra tools to get a project that only uses standard module types to build and run.
I haven't ever seen JSON files emitted. Is this true of plain I hope that helps. I have a bias towards standard module types and semantics just working, but I think that leads to mostly obvious answers to the questions here - differentiating standard from non-standard behavior being possibly the trickiest question. |
Suggestion
π Search Terms
import attributes, import assertions, ambient module
β Viability Checklist
My suggestion meets these guidelines:
β Suggestion
Following the suggestion at #40694 (comment)
Allow projects to declare ambient modules based on the import attributes. Such as:
π Motivating Example
Currently frontend build tools use file extensions and URL query strings to support all kinds of custom modules that are eventually compiled into JavaScript.
For example, in Vite (webpack supports these features in a similar way), we support JS modules importing
.module.css
files as CSS modules, and adding?url
postfixes to the imported path means we are to import the asset's real URL after bundling.That is:
But:
One thing that blocks us from doing so is the ability to declare ambient modules based on import assertions in TypeScript.
We can easily have type definitions for files based on their file extensions and query strings. In vite we have: https://github.com/vitejs/vite/blob/b690810f555549e9eed4b03600b27fe7649d6b07/packages/vite/client.d.ts
But currently, I don't see a way to migrate these type definitions when we move to import assertions.
π» Use Cases
declare module '*' assert {type: 'json'}
anddeclare module '*' assert {type: 'css'}
in the DOM lib.The text was updated successfully, but these errors were encountered: