My TypeScript 7.1 Beta example passed the compiler. The imported file did not exist. Running the emitted JavaScript failed with ERR_MODULE_NOT_FOUND.
That result is a useful way to understand the beta's new ambient module declarations: they describe how an import should be typed. They do not prove that its target exists. ๐ก
Results from my small compiler check using TypeScript 7.1.0-beta. The runtime failure deliberately uses a nonexistent file.
The new declaration follows the attribute
TypeScript's October 20 announcement adds import attributes to ambient module declarations. That lets a project describe a module selected by an attribute, instead of repeating declarations for every file extension. These declarations are supplied by the project; the beta does not add them to its built-in libraries. [1]
Here is the complete declaration I used in assets.d.ts:
declare module "*" with { type: "text" } {
const content: string;
export default content;
}
And the import in good.ts:
import note from "./missing.txt" with { type: "text" };
const upper: string = note.toUpperCase();
console.log(upper);
The compiler accepts the import and treats note as a string. The deliberate filename is a clue to the next boundary. ๐
Reproduce the compiler result
In an empty project with Node and npm available, install the exact beta I checked:
npm install --save-dev typescript@7.1.0-beta
npx tsc --ignoreConfig --module esnext --target es2022 --strict --noEmit assets.d.ts good.ts
I checked these cases with the same compiler options:
| Import form | Compiler result |
|---|---|
with { type: "text" } |
Passed |
| Attribute omitted | Failed |
with { type: "bytes" } |
Failed |
The declaration only supplies the text case. It gives the compiler no matching declaration for the other imports in this fixture. โ
That makes the attribute useful at the development boundary: a project can require the import form its tooling expects, and code gets the corresponding type.
Now cross the runtime boundary
I emitted the accepted case with:
npx tsc --ignoreConfig --module esnext --target es2022 --strict --outDir dist assets.d.ts good.ts
With {"type":"module"} in dist/package.json, node dist/good.js failed because missing.txt was absent. The runtime check used Node 22.22.1. It does not demonstrate a working text-import implementation.
The compiler did exactly what the declaration asked: it gave the matching import a type. It did not find or create the file. Microsoft's announcement explicitly documents that ambient matches do not validate file lookups. [1]
โ ๏ธ An ambient declaration is easy to mistake for a loader configuration. It supplies neither the asset nor the runtime behavior. Keep the build or runtime check that proves your real asset-loading route works.
Where I would use this
In a project whose bundler or runtime already supports attribute-based loading, I would describe that established behavior with a narrowly chosen declaration. Then I would run a small real import through the build as well as through the type checker.
For this fixture, the useful result is the boundary itself: the matching attribute gets checked, while file availability remains another tool's job. ๐งช
References
- Microsoft: Announcing TypeScript 7.1 Beta, October 20, 2026.
Asset credit: original diagram generated from the saved compiler outcomes. No speed benchmark or production compatibility claim.
AI disclosure
AI was used to draft the article.

Top comments (0)