TypeScript 7.1 可檢查 import 屬性,仍可能漏掉不存在的檔案
TypeScript 7.1 can check an import attribute and still miss a missing file
TypeScript 7.1.0-beta 可按 ambient module declaration 檢查符合條件的 import,並為匯入內容提供相應型別,但不會確認目標檔案是否存在。即使編譯通過,缺少 missing.txt 仍會令輸出的 JavaScript 在 Node 22.22.1 執行時因 ERR_MODULE_NOT_FOUND 而失敗。
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.
來源:DEV Community · dev.to
