Description
TypeScript Version: 2.1.4
Code
interface MutableValue<T> {
value: T;
}
interface ImmutableValue<T> {
readonly value: T;
}
let i: ImmutableValue<string> = { value: "hi" };
i.value = "Excellent, I can't change it"; // compile-time error
let m: MutableValue<string> = 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<number> = 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<T> {
getValue(): T;
setValue(v: T): void;
}
interface ImmutableValue<T> {
getValue(): T;
}
declare let i: ImmutableValue<string>;
i.setValue("Excellent, I can't change it"); // compile-time error
let m: MutableValue<string> = 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).