Using TypeScript, is there any way to enforce non-reassignment?
Say I have this:
fn.foo = 5;
fn.foo = 6;
is there a way to get a compile error on the second line? As soon as I assign the foo property, it should be ReadOnly
I suppose.
My case foo could adhere to this interface:
export interface RO {
[readonly key: string]: any
}
but I am not sure if that syntax works out.
If you use a class you can mark the field itself as readonly
and you can only assign it in the constructor:
class Test {
readonly foo : string;
constructor () {
this.foo = "";
}
}
let fn = new Test();
fn.foo = "" // Error
If you are using object literals you can use an explicit type to not allow mutation of a field just it's initial assignment:
let fn : {
readonly foo: string
} = {
foo: "1"
}
You could also use Object.freeze
which has runtime behavior as well:
let fn = Object.freeze({
foo: "1"
})
fn.foo = "" // error
In either case you can create a readonly
field that is only assignable on object creation. There is no way to create a field that is only assignable once after initialization such as in your example.
Edit
Note that readonly
is not very strong,it does nto cause type incompatibility between two types with the same fields:
let fn = Object.freeze({
foo: "1"
}) // foo is readonly
let nonReadonlyFn : { foo: string } =fn; // foo is not readonly but assignment is allowed
nonReadonlyFn.foo = "" // not a compiler error.
Update
If you don't know the keys you can create a readonly index signature:
let fn: {
readonly [n: string] : string
} = { foo: "" };
fn["foo"] ="" // error
console.log(fn["foo"])
A common way to create readonly objects without initializing them all at once is to have a mutable version, mutate it and when you are done assigning it to a readonly version:
let fnNotReadOnly: {
[n: string] : string
} ;
fnNotReadOnly["foo"] = "";
//When done mutating:
let fn : {
readonly [n: string] : string
} = fnNotReadOnly;
fn["foo"] = ""
console.log(fn["foo"])