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.
