Rule 8.14
Chapter 8, Functions and entry points Test
A constructor’s parameter property (constructor(public x: f32), or private, protected or readonly in place of public) is a field of its class, at the constructor’s place among the members, which the constructor assigns from the parameter before the field initializers run.
A field written without a type must take the type its initializer names (a written number is an f32 by Rule 5.1, true and false a bool, new C() the struct C, and a type’s own constructor that type), and a field whose initializer names none, or that has neither, must be refused.
A readonly field may be assigned only in a constructor of the class that declares it, which is TypeScript’s rule; readonly is shallow, as TypeScript’s is, so a write into what the field holds stands.
Field initializers must run in TypeScript’s order: those of the classes above the class whose constructor runs first (in the base constructor its super(...) calls, or before its body when none of them has one), that class’s parameter properties and its own after super(...) returns, and those of the classes below it when its body returns, so an initializer a derived class writes for an inherited field runs last.
The rule text and the parts under it are the compiler's own English, as the design document writes them.
Rationale
all three are how a TypeScript class is ordinarily written; before this rule a field without a type was dropped from the struct with nothing said where it was declared and an unknown field at every use, and a readonly field took any write. Every initializer ran before the constructor’s body and a derived class’s one for an inherited field was dropped, so class B extends A { limit = 5. } built a B whose limit was A’s.
Derives from
TypeScript’s parameter properties and readonly modifier (TS2540); Rule 5.1; Rule 6.9; surface §26.
How it is verified
Checked by a test. A test, a gate script or a CI workflow names this rule, and the traceability check fails when a file listed below stops naming it.
Where the rule says the compiler enforces it:
TS8010 STRUCT_FIELD for a field with no type, TS8005 CONST_ASSIGN for a write to a readonly field, pinned by src/compiler/ts/class-syntax.test.ts.
The files that verify it at commit 26de7be8, each at the first line that names the rule:
Explained in
The sections of the surface document that explain this rule, at commit 26de7be8:
Error codes that enforce it
The diagnostic codes the rule names under Enforced by, or whose registry text names the rule:
See also
Source
The rule at commit 26de7be8:
docs/language-design.md:751(the design document)reqs/rules/RULE-0814.md(its traceability item)