mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-03 07:54:40 +08:00
SC6001 only looked at call arguments and typed initializers, and only at strict field subsets: a target that adds optional properties, the empty record type, `r as T`, a later `v = r` into a typed binding, and records stored as elements of a typed array literal copied silently. The scan now reports a copy whenever the property sets differ, covers those sites, and reports a class instance that reaches a plain record type which does not keep its identity (the remaining boundary: interfaces of only generic methods). Every corpus program still reports no divergence.
40 lines
1.1 KiB
TypeScript
40 lines
1.1 KiB
TypeScript
// Record width copies beyond parameters and typed initializers: each site
|
|
// stores a record in a narrower or differently shaped record type, and the
|
|
// program then writes through or compares the copy.
|
|
interface Labeled {
|
|
label: string;
|
|
}
|
|
interface Tagged {
|
|
label: string;
|
|
tag: string;
|
|
}
|
|
interface Noted {
|
|
label: string;
|
|
note?: string;
|
|
}
|
|
const tagged: Tagged = { label: "first", tag: "t" };
|
|
|
|
// A target that adds an optional property is a different shape: a copy.
|
|
function annotate(target: Noted): void {
|
|
target.label = "noted";
|
|
}
|
|
annotate(tagged);
|
|
|
|
// The empty record type keeps no property, and no identity either.
|
|
const anything: {} = tagged;
|
|
console.log(anything === tagged);
|
|
|
|
// An assertion to a narrower record type copies as well.
|
|
const asserted = tagged as Labeled;
|
|
asserted.label = "asserted";
|
|
|
|
// So does a later assignment to a binding declared with that type.
|
|
let later: Labeled = { label: "later" };
|
|
later = tagged;
|
|
later.label = "assigned";
|
|
|
|
// Array elements are stored as copies of the element type.
|
|
const list: Labeled[] = [tagged];
|
|
for (const item of list) item.label = "element";
|
|
console.log(tagged.label);
|