Skip to content

Conversation

@jonathantneal
Copy link

@jonathantneal jonathantneal commented Jan 22, 2026

Summary

This PR adds complete support for import attributes in ambient module declarations, including syntax, semantic behavior, and diagnostics.

// Declare ambient module with import attributes
declare module '*.css' with { type: 'css' } {
  const stylesheet: CSSStyleSheet;
  export default stylesheet;
}

// Import with matching attributes - resolves correctly
import styles from 'styles.css' with { type: 'css' };
// styles: CSSStyleSheet ✅

// Import without attributes - doesn't match
import styles2 from 'styles2.css';
// styles2: any ❌
// Error TS18063: No ambient module declaration matches import of 'styles2.css' with the specified import attributes.

Implementation

Phase 1: Syntax Support

  • Reuses existing ImportAttributes infrastructure from import statements
  • Adds optional withClause field to ModuleDeclaration AST nodes
  • Updates parser to recognize with { ... } syntax after module name
  • Updates factory, emitter, and visitor functions to preserve the clause

Phase 2: Semantic Behavior

  • Module Resolution: Imports with attributes now match ambient declarations with matching attributes
  • Type Checking: Imports get correct types from matching ambient declarations
  • Attribute Matching Logic:
    • Exact match required: same keys and values
    • If neither has attributes, they match
    • If only one has attributes, they don't match
    • Works for both exact module names and wildcard patterns (*.css)

Phase 3: Validation & Diagnostics

  • New Error TS18063: "No ambient module declaration matches import of '{0}' with the specified import attributes."
  • New Error TS18062: "Module '{0}' was resolved to '{1}', but import attributes do not match the ambient module declaration."
  • Helpful error messages when imports don't match declarations due to attribute mismatches

Testing

  • Syntax tests: Verify parsing and emission of import attributes in ambient modules
  • Semantic tests: Verify imports match declarations based on attributes
  • Diagnostic tests: Verify appropriate error messages for mismatches
  • All tests passing: 99,248 out of 99,252 tests (4 pre-existing macOS symlink failures)
  • Public API baseline updated

Use Cases

This enables TypeScript to properly type imports based on their attributes:

// CSS Modules
declare module '*.css' with { type: 'css' } {
  const stylesheet: CSSStyleSheet;
  export default stylesheet;
}

// JSON imports
declare module '*.json' with { type: 'json' } {
  const data: any;
  export default data;
}

// WebAssembly modules
declare module '*.wasm' with { type: 'module' } {
  const module: WebAssembly.Module;
  export default module;
}

Related

  • Aligns with TC39 Import Attributes proposal
  • Enables better typing for module formats that require import attributes
  • Foundation for future enhancements to module resolution

Enables syntax: declare module "*.css" with { type: "css" } { ... }
Reuses existing ImportAttributes infrastructure from import statements.
Copilot AI review requested due to automatic review settings January 22, 2026 05:36
@typescript-bot typescript-bot added the For Uncommitted Bug PR for untriaged, rejected, closed or missing bug label Jan 22, 2026
@github-project-automation github-project-automation bot moved this to Not started in PR Backlog Jan 22, 2026
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

1 similar comment
@typescript-bot
Copy link
Collaborator

This PR doesn't have any linked issues. Please open an issue that references this PR. From there we can discuss and prioritise.

@typescript-bot
Copy link
Collaborator

Looks like you're introducing a change to the public API surface area. If this includes breaking changes, please document them on our wiki's API Breaking Changes page.

Also, please make sure @DanielRosenwasser and @RyanCavanaugh are aware of the changes, just as a heads up.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for import attributes syntax in ambient module declarations, enabling developers to specify import attributes (e.g., with { type: 'css' }) when declaring ambient modules. This is a syntax-only change that lays the foundation for future semantic behavior.

Changes:

  • Added optional withClause field to ModuleDeclaration AST nodes
  • Updated parser to recognize and parse with { ... } syntax after ambient module names
  • Updated factory, emitter, visitor, and transformer functions to handle the new field
  • Added comprehensive test coverage with baselines

Reviewed changes

Copilot reviewed 11 out of 12 changed files in this pull request and generated no comments.

Show a summary per file
File Description
tests/cases/conformance/ambient/ambientModuleWithImportAttributes.ts New test file demonstrating various uses of import attributes in ambient module declarations
tests/baselines/reference/api/typescript.d.ts Public API baseline updated with new withClause parameter in factory methods and parent type
tests/baselines/reference/ambientModuleWithImportAttributes.types Type baseline showing type inference works correctly
tests/baselines/reference/ambientModuleWithImportAttributes.symbols Symbol baseline showing symbol resolution works correctly
tests/baselines/reference/ambientModuleWithImportAttributes.js JavaScript output baseline showing modules are properly emitted
tests/baselines/reference/ambientModuleWithImportAttributes.errors.txt Error baseline showing expected module resolution errors
src/compiler/visitorPublic.ts Updated visitor to visit withClause field when traversing ModuleDeclaration nodes
src/compiler/types.ts Added withClause field to ModuleDeclaration interface and updated parent type for ImportAttributes
src/compiler/transformers/declarations.ts Updated transformer to preserve withClause when creating and updating module declarations
src/compiler/parser.ts Added parsing logic to recognize import attributes after ambient module names
src/compiler/factory/nodeFactory.ts Updated factory methods to accept and handle withClause parameter
src/compiler/emitter.ts Updated emitter to output withClause when emitting module declarations
Comments suppressed due to low confidence (1)

src/compiler/factory/nodeFactory.ts:4566

  • The withClause field should have its transform flags propagated in the non-ambient module case for consistency with how other optional child nodes like body are handled. Add propagateChildFlags(node.withClause) to the transform flags calculation on line 4561-4564.

While ambient modules (which have the simplified transform flags on line 4558) won't be affected since they overwrite the flags, propagating the flags ensures correctness if the factory API is used to create non-ambient module declarations with a withClause (even though the parser doesn't do this).

        node.withClause = withClause;
        if (modifiersToFlags(node.modifiers) & ModifierFlags.Ambient) {
            node.transformFlags = TransformFlags.ContainsTypeScript;
        }
        else {
            node.transformFlags |= propagateChildrenFlags(node.modifiers) |
                propagateChildFlags(node.name) |
                propagateChildFlags(node.body) |
                TransformFlags.ContainsTypeScript;
        }
        node.transformFlags &= ~TransformFlags.ContainsPossibleTopLevelAwait; // Module declarations cannot contain `await`.

@jonathantneal
Copy link
Author

@microsoft-github-policy-service agree

…tions

Implements module resolution and type checking to match imports with
attributes to ambient module declarations with matching attributes.

Changes:
- Added importAttributesMatch() helper to compare import attributes
- Added getImportAttributesFromLocation() to extract attributes from imports
- Updated tryFindAmbientModule() to check attribute matching for exact matches
- Updated resolveExternalModule() to check attribute matching for pattern matches
- Added comprehensive test coverage for all matching scenarios

Imports now properly resolve to ambient declarations only when attributes match:
- import x from 'foo.css' with { type: 'css' } matches declare module '*.css' with { type: 'css' }
- import x from 'foo.css' does NOT match declare module '*.css' with { type: 'css' }
- Mismatched, missing, or extra attributes result in no match (type: any)
Implements error reporting when import attributes don't match between
import statements and ambient module declarations.

Changes:
- Added diagnostic messages TS18062 and TS18063 for attribute mismatches
- Updated resolveExternalModule to report TS18063 when pattern matches
  but attributes don't match
- Created comprehensive test cases for diagnostic error messages

The diagnostic TS18063 is reported when:
- Pattern matches but attribute values are different
- Pattern matches but import has no attributes when declaration requires them
- Pattern matches but import has attributes when declaration doesn't
- Pattern matches but attributes have different keys or values
@jonathantneal jonathantneal force-pushed the jon/support-improt-attributes-in-ambient-module-declarations branch from 447ed44 to bac802a Compare January 22, 2026 07:11
The test harness validates that all child nodes are visited by forEachChild
in the correct order (by position in the source code).

We added withClause to ModuleDeclaration but:
1. Forgot to update the forEachChild visitor in parser.ts to include it
2. Had it in the wrong order - withClause comes BEFORE body in the syntax

The syntax is: declare module "name" with { ... } { ... }
So the order is: modifiers → name → withClause → body

This commit adds withClause to forEachChild in the correct position.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

2 participants