Now, TS would warn us that "'b' is specified more than once, so this usage will be overwritten". And if we remove b property -- "Type 'number' is not assignable to type 'string'"
Another "fix" would be to avoid using spread operator and specify every property manually .
Both of these solutions are far from ideal, I agree.
---
I don't advocate TS in this thread though; I genuinely want to understand what makes row polymorphism different, and after reading several articles and harassing Claude Sonnet about it, I still didn't grasp what row polymorphism allows over what TS has.
As far as I understand it, row polymorphism wouldn’t allow the given example. Or to put it another way, the spread operator is impossible to type soundly in the presence of structural subtyping because the type system doesn’t capture the “openness” of the record’s type, the potential presence of additional fields. Whereas with row polymorphism, to some degree or another, you can.
const r1: { a: number; b: number } = { a: 10, b: 20 };
const r2: { a: number } = r1;
const r3: { a: number; b: string } = { b: "hello", ...r2 };
console.log(r3.b) // typescript thinks it's a string, but actually it's a number