microsoft/TypeScript (original) (raw)

TypeScript Version: 2.1.4

Code

interface MutableValue { value: T; }

interface ImmutableValue { readonly value: T; }

let i: ImmutableValue = { value: "hi" }; i.value = "Excellent, I can't change it"; // compile-time error

let m: MutableValue = i; m.value = "Oh dear, I can change it";

Expected behavior:
The assignment of i to m would fail, to stop us accidentally allowing value to be modified.

Actual behavior:
The assignment is allowed.

The current behaviour was a deliberate choice so this is a breaking change (or strict flag) feature request rather than a bug report!

The Handbook has this snippet:

let a: number[] = [1, 2, 3, 4]; let ro: ReadonlyArray = a; ro[0] = 12; // error! ro.push(5); // error! ro.length = 100; // error! a = ro; // error!

It notes that a = ro being an error is helpful. But this happens because ReadonlyArray has no push method, making it incompatible with Array.

My example above seems "morally equivalent" to modelling the input/output flow of values with separate methods:

interface MutableValue { getValue(): T; setValue(v: T): void; }

interface ImmutableValue { getValue(): T; }

declare let i: ImmutableValue; i.setValue("Excellent, I can't change it"); // compile-time error

let m: MutableValue = i; m.setValue("Oh dear, I can change it");

And sure enough, this stops the assignment of i to m.

Would be great if mutable and readonly properties had the same relationship as if they were modelled by separate get/set methods (which of course they might actually be, via property getter/setters).