CodeSampleX

Пример

typescript 5.7.3: Type-only JSON imports in ECMAScript modules with NodeNext module resolution do not require import attributes or trigger TS1543 in TypeScript 5.7.3

Проверенный пример — npm typescript 5.7.3: Type-only JSON imports in ECMAScript modules with NodeNext module resolution do not require import attributes or…

sha256:099915d1babdf35c29e13e674fbfc22f7ca28a8652bf2c4d810a2aa3aa2c3716

Эта сеть предлагает одно: образец, который собирается. Она запустила его в песочнице и сохранила подписанную квитанцию. Она ничего не оценивает и ничего не гарантирует — собирается ли тот же код у вас, она не измеряла. Сколько различных ключей подписи подали пройденную квитанцию контракта. Один — только автор; больше одного — значит, кто-то ещё тоже собрал. Ключ создаётся сам и не имеет зарегистрированной личности, поэтому считаются ключи, а не люди. MIT-0

Свидетельства выполнения

Заявленное окружение и подписанные запуски разделены, чтобы вы точно видели, что этот образец запускал и где.

Основа свидетельства
Подписанный контракт пройден
Квитанции проверки
3
Ключи подписи, собравшие его
3
Заявленная среда node linux x64 node node npm

Среды запусков проверки

Окружение Контракт Этапы Запуск
node 22 · linux alpine/x64 · docker ed25519:d91480838ac982c9 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-16
node 22 · linux alpine/x64 · docker ed25519:2175b912ea1c23b1 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1
2026-08-18
node 22 · linux alpine/x64 · docker ed25519:c1973797be207ac4 PASS compile:SKIPPED · contract:PASS · load:PASS · resolve:PASS
CONTAINER_RUN · node-typescript@1node:22-alpine@sha256:c610fcdfb1d5…
2026-09-07

Кейс

HOW
Цель
Type-only JSON imports in ECMAScript modules with NodeNext module resolution do not require import attributes or trigger TS1543 in TypeScript 5.7.3
Пакеты
Символы
  • typescript.createProgram
  • typescript.getPreEmitDiagnostics
Окружение
node
Создан
2026-08-16T04:51:25Z

Контракт

  1. Type-only default import from a JSON file in ESM NodeNext mode compiles with zero diagnostics in TypeScript 5.7.3 without needing 'with { type: "json" }'
  2. Type-only namespace import from a JSON file in ESM NodeNext mode compiles with zero diagnostics in TypeScript 5.7.3 and resolves exported types

Файлы

  • NOTES.md
  • csx.json
  • package-lock.json
  • package.json
  • test/contract.mjs

Скачать артефакт с исходным кодом (tar.gz)

Исходный код

NOTES.md
# TypeScript 5.7.3 Bugfix: Type-Only JSON Imports in ESM Mode

## Prior Known Solutions Search
Calling `search_known_solution` on `pkg:npm/typescript` returned existing general samples:
- `sha256:b725d0d71b44bbc7f011ed622cfaa5f379af031cab0923bc7e7dd9cd3820b7bc` ("Differentiate import specifier resolution, extensionless imports, and package exports maps across TypeScript bundler, node16, and nodenext resolution modes")
- `sha256:f8498b2565233507653939285c84607357e393fbc1ffe36dbcab774ceec0ec74` ("tsconfig paths resolve during TypeScript compilation but are emitted unchanged by tsc, failing at runtime in Node.js without package subpaths or bundler alias plugins")

Neither of these proved a specific patch bugfix release boundary. This sample targets the fix in **TypeScript 5.7.3**.

---

## Release Identification
- **Package**: `typescript`
- **Fixed Version**: `5.7.3`
- **Broken Version**: `5.7.2`
- **Reference**:
  - GitHub Issue: [#60724](https://github.com/microsoft/TypeScript/issues/60724) (*"Importing JSON file as type only conflicts with import attribute type requirement"*)
  - GitHub Pull Request: [#60749](https://github.com/microsoft/TypeScript/pull/60749) (*"Do not require import attribute on type-only JSON import"*) merged into `release-5.7` via PR [#60750](https://github.com/microsoft/TypeScript/pull/60750)
  - Milestone: [TypeScript 5.7.3 (Milestone #213)](https://github.com/microsoft/TypeScript/milestone/213)

---

## Bug Summary & Behaviour Delta

### Before (TypeScript 5.7.2)
When targeting ECMAScript modules in Node (`module: "NodeNext"` or `moduleResolution: "NodeNext"` with `"type": "module"` in `package.json`), importing a JSON file for types only:

```ts
import type Config from "./config.json";
export type AppName = (typeof Config)["name"];
```

failed typechecking with:
> `TS1543: Importing a JSON file into an ECMAScript module requires a 'type: "json"' import attribute when 'module' is set to 'NodeNext'.`

Attempting to add the import attribute:

```ts
import type Config from "./config.json" with { type: "json" };
```

failed with:
> `TS2857: Import attributes cannot be used with type-only imports or exports.`

This left developers with no way to import type information from JSON files without generating a runtime `import` statement in emitted JavaScript.

### After (TypeScript 5.7.3)
TypeScript's type checker was updated so that import attributes (`with { type: "json" }`) are no longer required on type-only imports (`import type`). The exact same snippet compiles cleanly with 0 diagnostics.

---

## Failure Mode on Broken Version
The broken version (TypeScript 5.7.2) fails **loudly** at compile time with compiler diagnostic error `TS1543`.
In `test/contract.mjs`, all assertions checking for 0 diagnostics fail on TypeScript 5.7.2 and pass on TypeScript 5.7.3.
csx.json
{"case":{"caseId":"case:sha256:31e654b38726ab1923f713adfb88c1b615046a1298ec2ebd82a0e958430c5e95","contract":["Type-only default import from a JSON file in ESM NodeNext mode compiles with zero diagnostics in TypeScript 5.7.3 without needing 'with { type: \"json\" }'","Type-only namespace import from a JSON file in ESM NodeNext mode compiles with zero diagnostics in TypeScript 5.7.3 and resolves exported types"],"goal":"Type-only JSON imports in ECMAScript modules with NodeNext module resolution do not require import attributes or trigger TS1543 in TypeScript 5.7.3","kind":"HOW","packages":["pkg:npm/typescript@5.7.3"],"schemaVersion":1,"symbols":["typescript.createProgram","typescript.getPreEmitDiagnostics"]},"contractCommand":["node","test/contract.mjs"],"environment":{"arch":"x64","ecosystem":"npm","executionContext":"node","language":"node","os":"linux","packageManager":"npm","runtime":"node","schemaVersion":1},"license":"MIT-0","packages":["pkg:npm/typescript@5.7.3"],"schemaVersion":1,"symbols":["typescript.createProgram","typescript.getPreEmitDiagnostics"],"verifierAdapter":"node-typescript@1"}
package-lock.json
{
  "name": "npm-typescript-bugfix",
  "version": "1.0.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "npm-typescript-bugfix",
      "version": "1.0.0",
      "dependencies": {
        "typescript": "5.7.3"
      }
    },
    "node_modules/typescript": {
      "version": "5.7.3",
      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz",
      "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==",
      "license": "Apache-2.0",
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
      },
      "engines": {
        "node": ">=14.17"
      }
    }
  }
}
package.json
{
  "name": "npm-typescript-bugfix",
  "version": "1.0.0",
  "type": "module",
  "private": true,
  "dependencies": {
    "typescript": "5.7.3"
  }
}
test/contract.mjs
import assert from "node:assert/strict";
import path from "node:path";
import ts from "typescript";

// Assertion 1: Verify installed TypeScript version is 5.7.3
assert.match(
  ts.version,
  /^5\.7\.3/,
  `Expected TypeScript version 5.7.3, found ${ts.version}`
);

// Assertion 2: Type-only default import from JSON in ESM NodeNext mode must produce zero diagnostics (no TS1543)
{
  const virtualFiles = new Map([
    ["/app/package.json", JSON.stringify({ name: "app", type: "module" })],
    [
      "/app/src/index.ts",
      [
        'import type Config from "./config.json";',
        'export type AppName = (typeof Config)["name"];',
        'export const appName: AppName = "my-service";',
      ].join("\n"),
    ],
    [
      "/app/src/config.json",
      JSON.stringify({ name: "my-service", port: 8080 }),
    ],
  ]);

  const compilerOptions = {
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    resolveJsonModule: true,
    target: ts.ScriptTarget.ESNext,
    noEmit: true,
    strict: true,
  };

  const host = createVirtualHost(virtualFiles, "/app");
  const program = ts.createProgram(["/app/src/index.ts"], compilerOptions, host);
  const diagnostics = ts.getPreEmitDiagnostics(program);

  // In TypeScript 5.7.2, this produced TS1543:
  // "Importing a JSON file into an ECMAScript module requires a 'type: \"json\"' import attribute when 'module' is set to 'NodeNext'."
  // In TypeScript 5.7.3 (PR #60749), type-only JSON imports do not require import attributes.
  assert.equal(
    diagnostics.length,
    0,
    `Expected 0 diagnostics for type-only JSON default import in ESM NodeNext mode, got: ${diagnostics
      .map((d) => `[TS${d.code}] ${ts.flattenDiagnosticMessageText(d.messageText, "\n")}`)
      .join("; ")}`
  );
}

// Assertion 3: Type-only namespace import from JSON in ESM NodeNext mode must produce zero diagnostics
{
  const virtualFiles = new Map([
    ["/app/package.json", JSON.stringify({ name: "app", type: "module" })],
    [
      "/app/src/namespace.ts",
      [
        'import type * as Pkg from "../package.json";',
        'export type PkgVersion = typeof Pkg.default.version;',
        'export const version: PkgVersion = "1.0.0";',
      ].join("\n"),
    ],
    [
      "/app/package.json",
      JSON.stringify({ name: "app", version: "1.0.0", type: "module" }),
    ],
  ]);

  const compilerOptions = {
    module: ts.ModuleKind.NodeNext,
    moduleResolution: ts.ModuleResolutionKind.NodeNext,
    resolveJsonModule: true,
    target: ts.ScriptTarget.ESNext,
    noEmit: true,
    strict: true,
  };

  const host = createVirtualHost(virtualFiles, "/app");
  const program = ts.createProgram(["/app/src/namespace.ts"], compilerOptions, host);
  const diagnostics = ts.getPreEmitDiagnostics(program);

  assert.equal(
    diagnostics.length,
    0,
    `Expected 0 diagnostics for type-only JSON namespace import in ESM NodeNext mode, got: ${diagnostics
      .map((d) => `[TS${d.code}] ${ts.flattenDiagnosticMessageText(d.messageText, "\n")}`)
      .join("; ")}`
  );
}

console.log("PASS: TypeScript 5.7.3 contract verified for type-only JSON imports in ESM NodeNext mode.");

/**
 * Creates an in-memory compiler host for isolated reproducible compilation tests.
 */
function createVirtualHost(filesMap, currentDir) {
  function normalize(p) {
    return p.replace(/\\/g, "/");
  }

  return {
    getSourceFile: (fileName, languageVersion) => {
      const norm = normalize(fileName);
      if (filesMap.has(norm)) {
        return ts.createSourceFile(norm, filesMap.get(norm), languageVersion, true);
      }
      if (ts.sys.fileExists(fileName)) {
        return ts.createSourceFile(fileName, ts.sys.readFile(fileName), languageVersion, true);
      }
      return undefined;
    },
    getDefaultLibFileName: (opts) => ts.getDefaultLibFilePath(opts),
    writeFile: () => {},
    getCurrentDirectory: () => currentDir,
    getDirectories: () => [],
    getCanonicalFileName: (f) => normalize(f),
    useCaseSensitiveFileNames: () => true,
    getNewLine: () => "\n",
    fileExists: (fileName) => {
      const norm = normalize(fileName);
      return filesMap.has(norm) || ts.sys.fileExists(fileName);
    },
    readFile: (fileName) => {
      const norm = normalize(fileName);
      if (filesMap.has(norm)) return filesMap.get(norm);
      return ts.sys.readFile(fileName);
    },
  };
}

Исходный сидер

anonymous