Repository: TypeScript
Issue: Ambient Module Declarations for Import Attributes (formerly known as Import Assertions)
Labels: Suggestion,Awaiting More Feedback

# Suggestion

## 🔍 Search Terms

import attributes, import assertions, ambient module

## ✅ Viability Checklist

My suggestion meets these guidelines:

* [x] This wouldn't be a breaking change in existing TypeScript/JavaScript code
* [x] This wouldn't change the runtime behavior of existing JavaScript code
* [x] This could be implemented without emitting different JS based on the types of the expressions
* [x] This isn't a runtime feature (e.g., library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
* [x] This feature would agree with the rest of [TypeScript's Design Goals](https://github.com/Microsoft/TypeScript/wiki/TypeScript-Design-Goals).


## ⭐ Suggestion

<!-- A summary of what you'd like to see added or changed -->

Following the suggestion at https://github.com/microsoft/TypeScript/issues/40694#issuecomment-918343758
Allow projects to declare ambient modules based on the import attributes. Such as:

```ts
declare module '*' with {type: 'css'} {
  const stylesheet: CSSStyleSheet;
  export default stylesheet;
}
```

## 📃 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:
```js
// get the exported classes from a CSS module
import classes from './example.module.css'

// Explicitly load assets as URL
import assetAsURL from './asset.js?url'
```

But:
1. The extension approach may collide with new browser native features, such as [the native CSS modules](https://css-tricks.com/css-modules-the-native-ones/). So it's better to have a way to differentiate them. Import attributes could help in this case.
2. The query string approach is not a standard.
    - It alters the standard semantics of an import statement
    - Different tools vary on their choices of queries
    - Modules with such syntaxes won't be able to run separately without *the specific bundler*
    - So, we hope to migrate away from this approach and base the feature upon a standard. Import attributes seems to be the way to go.

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

<!--
  What do you want to use this for?
  What shortcomings exist with current approaches?
  What workarounds are you using in the meantime?
-->

1. The abovementioned frontend build tools.
2. Type definitions for browsers' built-in CSS & JSON modules support. We can have `declare module '*' assert {type: 'json'}` and `declare module '*' assert {type: 'css'}` in the DOM lib.