Make Properties and Index Signatures Readonly in TypeScript

Marius Schulz
InstructorMarius Schulz
Share this video with your friends

Social Share Links

Send Tweet
Published 7 years ago
Updated 3 years ago

TypeScript 2.0 introduced the readonly modifier which can be added to a property or index signature declaration. It helps prevent against unintended property assignments. This lesson gives various use cases for readonly and shows what the generated JavaScript code looks like.

In this lesson, I want to look at how can use TypeScript's read only keyword to prevent unintended property assignments. Let's assume we have defined an interface called user that has an ID property of type number and a name property of type string. Let's now create a user object and initialize the ID and name properties with some values.

After we've created the object, we can modify both properties whenever we like. Of course, our program is still type correct. While it's probably OK to change the name of a user, we definitely don't want somebody to change their ID later on.

If that is the case, we can go ahead and add the read only modifier to the ID property in our interface. If we now try to assign a new value to this ID property, we get a type error in 911, saying that we cannot assign to ID because it is a constant or a read only property. This way, TypeScript's type system helps us prevent unintended assignments.

Now let's take a look at the compiled output. I've already prepared a basic to use config JSON which writes all JavaScript files to the disk folder. Let's go ahead and run the compiler and then open up the TypeScript file and the JavaScript file side by side.

As you can see, the entire interface has been compiled away. There is no runtime manifestation of the read only keyword whatsoever. Read only is purely an artifact of the type system. The typescript compiler does not generate any sort of wrapping JavaScript code. Any piece of code that has access to the user object can still change its properties because the object is not magically frozen.

Let's now move in to ES2015 classes. Instead of an interface called user, we could have also written a user class. In this case, we would declare two fields, ID and name, of type number and string respectively. The constructor would then accept both values as parameters and assign them to their respective field.

If we now create an instance of the user class and pass in an ID and a name, we can still modify the properties after we've created the instance. This is because neither property is marked read only. So let's go ahead and add the read only modifier to the ID property. Now we can only assign to the ID property from within the constructor of the same class, which is why we get a type error in line 12.

Let's now see how the read only modifier can help us when we write index signatures. Take this array of weekdays for example. In JavaScript, arrays are mutable, so nobody is stopping me from doing something like this. Right now, TypeScript infers the weekdays variable to be of type string array because that's the type of the value that we initialized the variable with.

We can however explicitly declare the weekdays variable to be a read only array of strings. With this type annotation in place, we now get a type error in line 11 saying that the index signature in type read only array of string only permits reading.

Let's jump to the definition of the read only array type. Visual studio code takes me directly to the lib.d.ts file that ships as part of the TypeScript compiler. Read only array defines a bunch of array methods. Then at the very bottom, it defines an index signature that has the read only modifier applied to it. This is why we get a type error if we try to mutate the array.

We also can't empty the array by setting its length to zero. This is because the length property is marked read only as well, so we get a type error if we try to assign to it.

Finally, the read only array type only exposes non-destructive array methods, that is methods such as push or splice are missing so we don't mutate the array by accident. Once again, the compiler does not give you a truly immutable array. All of this is just a compile time protection. If we run the compiler again and then check out the generated JavaScript output, you can see that our read only array is compiled into a plain array.

Now we're in JavaScript land and anything goes.