Skip to content

Module resolution: ambient JSON wildcard module doesn't override resolveJsonModule typing #62924

@niedzielski

Description

@niedzielski

Demo Repo

https://github.com/niedzielski/2025-12-23-tsc-resolve-json-ambient-wildcard

Which of the following problems are you reporting?

The module specifier resolves to the right file, but something about the types are wrong

Demonstrate the defect described above with a code sample.

When resolveJsonModule is set, the imported JSON file's typing is used instead of the ambient module typing.

// schema-decl.d.ts
declare module '*.schema.json' {
  const json: import("./schema.js").Schema
  export default json
}
// index.ts
// Typed as JSON interpretation from file instead of ambient module.
import schemaJSON from './instance.schema.json' with { type: 'json' }
// tsconfig.json
{
  "compilerOptions": {
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "noEmit": true
  }
}

Run tsc --showConfig and paste its output here

{
    "compilerOptions": {
        "module": "esnext",
        "moduleResolution": "bundler",
        "resolveJsonModule": true,
        "noEmit": true,
        "allowSyntheticDefaultImports": true,
        "resolvePackageJsonExports": true,
        "resolvePackageJsonImports": true
    },
    "files": [
        "./index.ts",
        "./schema-decl.d.ts",
        "./schema.ts"
    ]
}

Run tsc --traceResolution and paste its output here

======== Resolving module './instance.schema.json' from '/home/user/desk/foo/index.ts'. ========
Explicitly specified module resolution kind: 'Bundler'.
Resolving in CJS mode with conditions 'import', 'types'.
Loading module as file / folder, candidate module location '/home/user/desk/foo/instance.schema.json', target file types: TypeScript, JavaScript, Declaration, JSON.
File name '/home/user/desk/foo/instance.schema.json' has a '.json' extension - stripping it.
File '/home/user/desk/foo/instance.schema.d.json.ts' does not exist.
File '/home/user/desk/foo/instance.schema.json' exists - use it as a name resolution result.
======== Module name './instance.schema.json' was successfully resolved to '/home/user/desk/foo/instance.schema.json'. ========
======== Resolving module './schema' from '/home/user/desk/foo/index.ts'. ========
Explicitly specified module resolution kind: 'Bundler'.
Resolving in CJS mode with conditions 'import', 'types'.
Loading module as file / folder, candidate module location '/home/user/desk/foo/schema', target file types: TypeScript, JavaScript, Declaration, JSON.
File '/home/user/desk/foo/schema.ts' exists - use it as a name resolution result.
======== Module name './schema' was successfully resolved to '/home/user/desk/foo/schema.ts'. ========
======== Resolving module './schema.js' from '/home/user/desk/foo/schema-decl.d.ts'. ========
Explicitly specified module resolution kind: 'Bundler'.
Resolving in CJS mode with conditions 'import', 'types'.
Loading module as file / folder, candidate module location '/home/user/desk/foo/schema.js', target file types: TypeScript, JavaScript, Declaration, JSON.
File name '/home/user/desk/foo/schema.js' has a '.js' extension - stripping it.
File '/home/user/desk/foo/schema.ts' exists - use it as a name resolution result.
======== Module name './schema.js' was successfully resolved to '/home/user/desk/foo/schema.ts'. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist.
Found 'package.json' at '/home/user/desk/foo/node_modules/typescript/package.json'.
======== Resolving module '@typescript/lib-es5' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.es5.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-es5' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-es5'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-es5'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-es5'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-es5'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-es5'
Loading module '@typescript/lib-es5' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-es5' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
======== Resolving module '@typescript/lib-decorators' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.decorators.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-decorators' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators'
Loading module '@typescript/lib-decorators' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-decorators' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
======== Resolving module '@typescript/lib-decorators/legacy' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.decorators.legacy.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-decorators/legacy' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators/legacy'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators/legacy'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators/legacy'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators/legacy'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-decorators/legacy'
Loading module '@typescript/lib-decorators/legacy' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-decorators/legacy' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
======== Resolving module '@typescript/lib-dom' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.dom.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-dom' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-dom'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-dom'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-dom'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-dom'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-dom'
Loading module '@typescript/lib-dom' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-dom' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
======== Resolving module '@typescript/lib-webworker/importscripts' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.webworker.importscripts.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-webworker/importscripts' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-webworker/importscripts'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-webworker/importscripts'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-webworker/importscripts'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-webworker/importscripts'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-webworker/importscripts'
Loading module '@typescript/lib-webworker/importscripts' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-webworker/importscripts' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
======== Resolving module '@typescript/lib-scripthost' from '/home/user/desk/foo/__lib_node_modules_lookup_lib.scripthost.d.ts__.ts'. ========
Explicitly specified module resolution kind: 'Node10'.
Loading module '@typescript/lib-scripthost' from 'node_modules' folder, target file types: TypeScript, Declaration.
Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.
Directory '/home/user/desk/foo/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-scripthost'
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-scripthost'
Directory '/home/user/node_modules/@types' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-scripthost'
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-scripthost'
Directory '/node_modules' does not exist, skipping all lookups in it.
Scoped package detected, looking in 'typescript__lib-scripthost'
Loading module '@typescript/lib-scripthost' from 'node_modules' folder, target file types: JavaScript.
Searching all ancestor node_modules directories for fallback extensions: JavaScript.
Directory '/home/user/desk/node_modules' does not exist, skipping all lookups in it.
Directory '/home/node_modules' does not exist, skipping all lookups in it.
Directory '/node_modules' does not exist, skipping all lookups in it.
======== Module name '@typescript/lib-scripthost' was not resolved. ========
File '/home/user/desk/foo/node_modules/typescript/lib/package.json' does not exist according to earlier cached lookups.
File '/home/user/desk/foo/node_modules/typescript/package.json' exists according to earlier cached lookups.
index.ts:4:14 - error TS2322: Type '{ name: string; type: string; }' is not assignable to type 'Schema'.
  Types of property 'type' are incompatible.
    Type 'string' is not assignable to type '"File" | "Folder"'.

4 export const schema: Schema = schemaJSON
               ~~~~~~

Found 1 error in index.ts:4

Paste the package.json of the importing module, if it exists

{
  "name": "foo",
  "version": "0.0.0",
  "main": "index.js",
  "scripts": {
    "test": "npx tsc"
  },
  "keywords": [],
  "author": "Stephen Niedzielski <[email protected]> (https://oidoid.com/)",
  "license": "AGPL-3.0-only",
  "description": "",
  "devDependencies": {
    "typescript": "5.9.3"
  }
}

Paste the package.json of the target module, if it exists

Same as importing module.

Any other comments can go here

Overriding JSON typing is an important feature for custom schemas. The workarounds now are:

  1. Cast.
  2. Use a non-JSON extension. For example, *.jsonc works.
  3. Disable resolveJsonModule.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions