From fcf213316de91703a8b91c1417723e4d72cbac36 Mon Sep 17 00:00:00 2001 From: erantianantha Date: Sun, 6 Sep 2026 01:12:31 +0530 Subject: [PATCH 1/2] Disallow 'readonly' modifier in ambient module import attributes types (#64143) Ambient module import attributes types should not accept the 'readonly' modifier. Adds diagnostic TS1558 ("An import attributes property cannot have a 'readonly' modifier.") and checks for modifiers in checkGrammarImportAttributesType. Fixes #64143. --- tsc/internal/checker/grammarchecks.go | 3 +++ .../diagnostics/diagnosticMessages.json | 4 +++ .../diagnostics/diagnostics_generated.go | 4 +++ .../importAttributeTypeReadonly.errors.txt | 25 +++++++++++++++++++ .../compiler/importAttributeTypeReadonly.ts | 21 ++++++++++++++++ 5 files changed, 57 insertions(+) create mode 100644 tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt create mode 100644 tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts diff --git a/tsc/internal/checker/grammarchecks.go b/tsc/internal/checker/grammarchecks.go index cc274d8b2fd4d..c9f5771398262 100644 --- a/tsc/internal/checker/grammarchecks.go +++ b/tsc/internal/checker/grammarchecks.go @@ -2207,6 +2207,9 @@ func (c *Checker) checkGrammarImportAttributesType(attributes *ast.TypeLiteralNo return c.grammarErrorOnNode(member, diagnostics.An_import_attributes_type_may_only_contain_property_signatures) } propertySignature := member.AsPropertySignatureDeclaration() + if propertySignature.Modifiers() != nil { + return c.grammarErrorOnNode(propertySignature.Modifiers().Nodes[0], diagnostics.An_import_attributes_property_cannot_have_a_readonly_modifier) + } if propertySignature.Type == nil { return c.grammarErrorOnNode(member, diagnostics.An_import_attributes_property_must_have_a_type_annotation) } diff --git a/tsc/internal/diagnostics/diagnosticMessages.json b/tsc/internal/diagnostics/diagnosticMessages.json index a52d38adbcc9c..95383075f4012 100644 --- a/tsc/internal/diagnostics/diagnosticMessages.json +++ b/tsc/internal/diagnostics/diagnosticMessages.json @@ -1876,6 +1876,10 @@ "category": "Error", "code": 1557 }, + "An import attributes property cannot have a 'readonly' modifier.": { + "category": "Error", + "code": 1558 + }, "The types of '{0}' are incompatible between these types.": { "category": "Error", diff --git a/tsc/internal/diagnostics/diagnostics_generated.go b/tsc/internal/diagnostics/diagnostics_generated.go index e323564b5d377..44194d9cca924 100644 --- a/tsc/internal/diagnostics/diagnostics_generated.go +++ b/tsc/internal/diagnostics/diagnostics_generated.go @@ -944,6 +944,8 @@ var An_import_attributes_property_cannot_be_optional = &Message{code: 1556, cate var X_0_is_not_a_valid_key_for_an_import_attributes_type = &Message{code: 1557, category: CategoryError, key: "_0_is_not_a_valid_key_for_an_import_attributes_type_1557", text: "'{0}' is not a valid key for an import attributes type."} +var An_import_attributes_property_cannot_have_a_readonly_modifier = &Message{code: 1558, category: CategoryError, key: "An_import_attributes_property_cannot_have_a_readonly_modifier_1558", text: "An import attributes property cannot have a 'readonly' modifier."} + var The_types_of_0_are_incompatible_between_these_types = &Message{code: 2200, category: CategoryError, key: "The_types_of_0_are_incompatible_between_these_types_2200", text: "The types of '{0}' are incompatible between these types."} var The_types_returned_by_0_are_incompatible_between_these_types = &Message{code: 2201, category: CategoryError, key: "The_types_returned_by_0_are_incompatible_between_these_types_2201", text: "The types returned by '{0}' are incompatible between these types."} @@ -5368,6 +5370,8 @@ func keyToMessage(key Key) *Message { return An_import_attributes_property_cannot_be_optional case "_0_is_not_a_valid_key_for_an_import_attributes_type_1557": return X_0_is_not_a_valid_key_for_an_import_attributes_type + case "An_import_attributes_property_cannot_have_a_readonly_modifier_1558": + return An_import_attributes_property_cannot_have_a_readonly_modifier case "The_types_of_0_are_incompatible_between_these_types_2200": return The_types_of_0_are_incompatible_between_these_types case "The_types_returned_by_0_are_incompatible_between_these_types_2201": diff --git a/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt b/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt new file mode 100644 index 0000000000000..73f9ec6727a54 --- /dev/null +++ b/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt @@ -0,0 +1,25 @@ +/readonlyError.d.ts(1,31): error TS1558: An import attributes property cannot have a 'readonly' modifier. +/readonlyError.d.ts(6,32): error TS1558: An import attributes property cannot have a 'readonly' modifier. + + +==== /readonlyError.d.ts (2 errors) ==== + declare module "*.css" with { readonly type: "css" } { + ~~~~~~~~ +!!! error TS1558: An import attributes property cannot have a 'readonly' modifier. + const stylesheet: CSSStyleSheet; + export default stylesheet; + } + + declare module "*.json" with { readonly type: "json", readonly kind: "data" } { + ~~~~~~~~ +!!! error TS1558: An import attributes property cannot have a 'readonly' modifier. + const data: any; + export default data; + } + +==== /valid.d.ts (0 errors) ==== + declare module "*.txt" with { type: "text" } { + const text: string; + export default text; + } + \ No newline at end of file diff --git a/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts b/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts new file mode 100644 index 0000000000000..659c99948188d --- /dev/null +++ b/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts @@ -0,0 +1,21 @@ +// @strict: true +// @module: preserve +// @noEmit: true +// @noTypesAndSymbols: true + +// @filename: /readonlyError.d.ts +declare module "*.css" with { readonly type: "css" } { + const stylesheet: CSSStyleSheet; + export default stylesheet; +} + +declare module "*.json" with { readonly type: "json", readonly kind: "data" } { + const data: any; + export default data; +} + +// @filename: /valid.d.ts +declare module "*.txt" with { type: "text" } { + const text: string; + export default text; +} From e06cb05791c89117ae2d405b32cfeb6752cfecfd Mon Sep 17 00:00:00 2001 From: erantianantha Date: Sun, 6 Sep 2026 01:23:20 +0530 Subject: [PATCH 2/2] Restrict modifier check to readonly keyword --- tsc/internal/checker/grammarchecks.go | 8 ++++++-- .../compiler/importAttributeTypeReadonly.errors.txt | 9 +++++++++ .../tests/cases/compiler/importAttributeTypeReadonly.ts | 6 ++++++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/tsc/internal/checker/grammarchecks.go b/tsc/internal/checker/grammarchecks.go index c9f5771398262..1c7430f2060b9 100644 --- a/tsc/internal/checker/grammarchecks.go +++ b/tsc/internal/checker/grammarchecks.go @@ -2207,8 +2207,12 @@ func (c *Checker) checkGrammarImportAttributesType(attributes *ast.TypeLiteralNo return c.grammarErrorOnNode(member, diagnostics.An_import_attributes_type_may_only_contain_property_signatures) } propertySignature := member.AsPropertySignatureDeclaration() - if propertySignature.Modifiers() != nil { - return c.grammarErrorOnNode(propertySignature.Modifiers().Nodes[0], diagnostics.An_import_attributes_property_cannot_have_a_readonly_modifier) + if modifiers := propertySignature.Modifiers(); modifiers != nil { + for _, modifier := range modifiers.Nodes { + if modifier.Kind == ast.KindReadonlyKeyword { + return c.grammarErrorOnNode(modifier, diagnostics.An_import_attributes_property_cannot_have_a_readonly_modifier) + } + } } if propertySignature.Type == nil { return c.grammarErrorOnNode(member, diagnostics.An_import_attributes_property_must_have_a_type_annotation) diff --git a/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt b/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt index 73f9ec6727a54..234039dba9dfa 100644 --- a/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt +++ b/tsc/testdata/baselines/reference/compiler/importAttributeTypeReadonly.errors.txt @@ -1,3 +1,4 @@ +/otherModifierError.d.ts(1,31): error TS1070: 'public' modifier cannot appear on a type member. /readonlyError.d.ts(1,31): error TS1558: An import attributes property cannot have a 'readonly' modifier. /readonlyError.d.ts(6,32): error TS1558: An import attributes property cannot have a 'readonly' modifier. @@ -17,6 +18,14 @@ export default data; } +==== /otherModifierError.d.ts (1 errors) ==== + declare module "*.svg" with { public type: "svg" } { + ~~~~~~ +!!! error TS1070: 'public' modifier cannot appear on a type member. + const content: string; + export default content; + } + ==== /valid.d.ts (0 errors) ==== declare module "*.txt" with { type: "text" } { const text: string; diff --git a/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts b/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts index 659c99948188d..94bbc6823e0b5 100644 --- a/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts +++ b/tsc/testdata/tests/cases/compiler/importAttributeTypeReadonly.ts @@ -14,6 +14,12 @@ declare module "*.json" with { readonly type: "json", readonly kind: "data" } { export default data; } +// @filename: /otherModifierError.d.ts +declare module "*.svg" with { public type: "svg" } { + const content: string; + export default content; +} + // @filename: /valid.d.ts declare module "*.txt" with { type: "text" } { const text: string;