mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-23 06:10:02 +08:00
- a !-asserted (or SPI-off) field first assigned past the constructor's top level rides an undefined-armed union slot: allocation writes the interned undefined, writes wrap, reads extract the declared type - scalar reads take unit defaults where JS-undefined behavior survives (bool false, f64 NaN — conditions and arithmetic exact); string/ref reads keep the checked-extraction trap, JS's own first-member-use TypeError named earlier - union/map/dyn-typed ! fields keep the fence; deferral propagates down the base chain with the fields map - diagnostics fixtures re-pin the surviving fences; corpus 2429 pins the Output.initialize idiom on both backends; SEMANTICS.md 372-375
36 lines
971 B
TypeScript
36 lines
971 B
TypeScript
// A project tsconfig with strictPropertyInitialization OFF (strict: false;
|
|
// strictNullChecks stays on — the floor): tsc no longer verifies that
|
|
// initializer-less fields are assigned in the constructor. An
|
|
// unconditionally ctor-assigned field compiles as ever (`Ok`); a field
|
|
// assigned only in a method now DEFERS like a `!` assertion (the slot
|
|
// rides `T | undefined`, reads extract — SEMANTICS.md 372), so `Bad`
|
|
// compiles too. The fence survives exactly where the deferral cannot
|
|
// carry the type: a MAP-typed field (map arms cannot join a union).
|
|
|
|
class Ok {
|
|
n: number;
|
|
s: string;
|
|
constructor(n: number) {
|
|
this.n = n;
|
|
this.s = "ok";
|
|
}
|
|
}
|
|
|
|
class Bad {
|
|
v: number; // compiles: deferred init (reads NaN until assigned)
|
|
m(): void {
|
|
this.v = 1;
|
|
}
|
|
}
|
|
|
|
class Worse {
|
|
m: Map<string, number>; // fenced: no deferral union for map fields
|
|
fill(): void {
|
|
this.m = new Map();
|
|
}
|
|
}
|
|
|
|
console.log(new Ok(5).n);
|
|
new Bad();
|
|
new Worse();
|