So apparently typescript allows you to remove the readonly modifier from a type by a simple assignment like so:
function foo(x: { readonly value: string }) {
x.value = "new value"; // This would fail, as it should
bar(x); // But this is okay?
}
function bar(x: { value: string }) {
x.value = "new value";
}
It seems to me that this would make it really easy to mutate a readonly field by accident, or am I missing something? Am I using readonly incorrectly? Is there any stricter alternative in typescript that would prohibit this kind of behavior?
EDIT: Since this is indeed how it works, here's a workaround that seems to help in my particular case, event though it's by no means a perfect solution:
type ConstAware<T> = { __writable: true } & { [P in keyof T]: T[P] };
type Const<T> = T extends ConstAware<any> ? { readonly [P in Exclude<keyof T, "__writable">]: T[P] } : never;
type Foo = ConstAware<{
value: string;
}>;
function foo(x: Const<Foo>) {
let y: Foo = x; // Not allowed, yay
y.value = "new value";
}
This is a known issue, documented here. The gist of it is that the readonly modifier does not impact assignability. This does limit the usefulness of the readonly modifier unfortunately.
There is no known way to make this stricter, no compiler option, and no clever type trick to do this. I am pretty confident of this proclamation since there is no way to discern in the type system that readonly s present on a type (either in conditional or mapped types). Without this ability we can't really introduce an error to not allow the assignment.
Note This was written when Typescript 3.1 was the current version, future versions of Typescript (I hope) might prove me wrong.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With