Part of #80. Follow-up to #121.
Context
#121 made class A { [x: string]: T } parse, but TryConsumeClassIndexSignature (Parser.Classes.cs:516) discards the parsed value type — it returns only a bool. So the class type carries no index signature: it isn't structurally compatible with index-signature targets, and a["k"] isn't typed. The assignmentCompatWith{String,Numeric}Indexer* tests reach the checker but produce wrong results.
Scope / approach
- AST (
AST.cs:381): add an IndexSignatures slot to Stmt.Class (reuse Stmt.IndexSignature, already used by interfaces).
- Parser (
Parser.Classes.cs:516): change TryConsumeClassIndexSignature to return the parsed key-type + value-type (don't discard); collect into the new slot in ClassDeclaration (Parser.Classes.cs:506).
ClassMetadataCore (ClassMetadataCore.cs:10): add StringIndexType / NumberIndexType / SymbolIndexType (optional defaulted). Update the 2 construction sites — MutableClass.FreezeCore (TypeInfo.cs:271) and generic substitution (Generics.MappedTypes.cs:179).
- Builder (
TypeChecker.Statements.Classes.cs:12 CheckClassDeclaration): resolve the index-signature value types and thread them into the core, alongside field/method collection (~lines 224-264).
- Read sites — add
TypeInfo.Class branches where index types are consulted (today only Record / Interface are handled):
- structural excess-property / assignability:
Compatibility.Structural.cs:53-85
- index access & assignability: the ~8 sites in
Properties.Index.cs (e.g. :153, :229, :240, :318, :420…).
Acceptance
class A { [x: string]: Base } is assignable to/from { [x: string]: Base } per TS rules.
- Index access
a["k"] on such a class is typed as the value type.
assignmentCompatWith{String,Numeric}Indexer* move out of Fail toward Pass (regen baseline; no regressions).
Blast radius
Medium. Positional-record changes to Stmt.Class and ClassMetadataCore (optional defaulted trailing params keep call sites compiling), but the ~10 index-read sites each need a new Class branch — mechanical but spread out. Best done as its own PR.
Sequencing
Independent of the call/signature follow-up; both build only on merged #121. That one is smaller/higher-leverage and should go first; this is meatier for a smaller (~6-test) cluster, so schedule as a standalone PR.
Part of #80. Follow-up to #121.
Context
#121 made
class A { [x: string]: T }parse, butTryConsumeClassIndexSignature(Parser.Classes.cs:516) discards the parsed value type — it returns only a bool. So the class type carries no index signature: it isn't structurally compatible with index-signature targets, anda["k"]isn't typed. TheassignmentCompatWith{String,Numeric}Indexer*tests reach the checker but produce wrong results.Scope / approach
AST.cs:381): add anIndexSignaturesslot toStmt.Class(reuseStmt.IndexSignature, already used by interfaces).Parser.Classes.cs:516): changeTryConsumeClassIndexSignatureto return the parsed key-type + value-type (don't discard); collect into the new slot inClassDeclaration(Parser.Classes.cs:506).ClassMetadataCore(ClassMetadataCore.cs:10): addStringIndexType/NumberIndexType/SymbolIndexType(optional defaulted). Update the 2 construction sites —MutableClass.FreezeCore(TypeInfo.cs:271) and generic substitution (Generics.MappedTypes.cs:179).TypeChecker.Statements.Classes.cs:12CheckClassDeclaration): resolve the index-signature value types and thread them into the core, alongside field/method collection (~lines 224-264).TypeInfo.Classbranches where index types are consulted (today onlyRecord/Interfaceare handled):Compatibility.Structural.cs:53-85Properties.Index.cs(e.g.:153,:229,:240,:318,:420…).Acceptance
class A { [x: string]: Base }is assignable to/from{ [x: string]: Base }per TS rules.a["k"]on such a class is typed as the value type.assignmentCompatWith{String,Numeric}Indexer*move out ofFailtowardPass(regen baseline; no regressions).Blast radius
Medium. Positional-record changes to
Stmt.ClassandClassMetadataCore(optional defaulted trailing params keep call sites compiling), but the ~10 index-read sites each need a newClassbranch — mechanical but spread out. Best done as its own PR.Sequencing
Independent of the call/signature follow-up; both build only on merged #121. That one is smaller/higher-leverage and should go first; this is meatier for a smaller (~6-test) cluster, so schedule as a standalone PR.