Learn TypeScript
Creating readonly objects and array properties
Creating readonly objects and array properties
In this lesson, we will learn how to create object types with readonly properties that are objects and arrays.
Understanding the readonly
modifier on reference types
The readonly
modifier can be placed before a property that is a reference type (i.e. an object or an array) as follows:
type TypeName = { readonly propertyName1: ObjectType; readonly propertyName2: ArrayType;};
This can also be used in interfaces and classes:
interface InterfaceName { readonly propertyName1: ObjectType; readonly propertyName2: ArrayType;}class ClassName { constructor( public readonly propertyName1: ObjectType, public readonly propertyName2: ArrayType ) {}}
This will stop the property's reference from changing so that it can't be changed to another object or array. It, however, doesn't stop values within the property from changing.
We can put an additional readonly
modifier before array type to prevent the array items from changing for array types.
readonly propertyName: readonly ArrayType;
For object types, we need to put an additional readonly
modifier before properties within the object to prevent them from changing.
type TypeName = { readonly propertyName: { readonly subPropertyName: PropertyType; };};
An example
We will explore the readonly
modifier on an object and array properties in the TypeScript playground.
- Open the TypeScript playground by clicking the link below:
- Paste the code from below into the TypeScript Playground:
interface Result { name: string; readonly scores: number[]; readonly profile: { level: number; };}let billScores: Result = { name: "Bill", scores: [90, 65, 80], profile: { level: 1, },};console.log(billScores);
The code contains a variable given a Result
type, which in tern has readonly array and object properties.
- Let's try to add a new value to the
scores
array property. Put the following line of code just before theconsole.log
statement in the editor.
billScores.scores.push(70);
Why isn't a type error raised on this line of code? How can we ensure a type error is raised?
- Now add a line of code to change the
level
property. Again, put the following line of code just before theconsole.log
statement in the editor.
billScores.profile.level = 2;
Why isn't a type error raised on this line of code? How can we ensure a type error is raised?
- Click the Run option in the TypeScript Playground and open the console.
Did the changes to the scores
array and level
take place at runtime?
Using the Readonly
utility type
There is a handy utility type called Readonly
that automatically adds the readonly
modifier to all the properties in an object type:
type ReadonlyType = Readonly<ExistingType>;
- Remove all the
readonly
modifiers from theResult
type:
interface Result { name: string; scores: number[]; profile: { level: number; };}
- Let's use the
Readonly
utility type on thebillScores
variable:
let billScores: Readonly<Result> = { name: "Bill", scores: [90, 65, 80], profile: { level: 1, },};
- Add a line of code to change the
name
property inbillScores
:
billScores.name = "Bob";
A type error occurs as we expect.
Why doesn't a type error occur on the other two assignments?
billScores.scores.push(70);billScores.profile.level = 2;
Summary
Care needs to be taken when adding the readonly
modifier to object and array properties. If the requirement is to make an array property value immutable, an additional readonly
modifier needs to be added before the array type. If the requirement is to make an object property value deep immutable, additional readonly
modifiers need to be added to all the nested properties.
Care also needs to be taken when using the Readonly
utility type. It is perfect for shallow object immutability but doesn't make an array or nested object properties immutable.
In the next lesson, we will learn how to make objects and arrays immutable at runtime and compile time.