I'd like to define a class which takes as one of of its constructor parameters an array of objects, and I'd like to provide the guarantee that neither the array nor the objects in it will be modified. My current attempt uses the readonly
modifier and the Readonly<T>
generic and looks something like this:
export type Foo = { foo: string };
export class Bar {
readonly foo: Foo;
readonly bars: Array<Readonly<Bar>>;
constructor(
foo: Readonly<Foo>,
bars: Readonly<Array<Readonly<Bar>>>,
) {
this.foo = foo;
this.bars = bars;
}
}
However, this gives an error on the line this.bars = bars;
, saying The type 'readonly Readonly<Bar>[]' is 'readonly' and cannot be assigned to the mutable type 'Readonly<Bar>[]'.ts(4104)
.
After some searching, I found a couple of answers which seem, if I understand them correctly, to indicate that mutable arrays and readonly
/Readonly<T>
arrays can't be assigned to one another.
How, then, can I represent the immutability contract I'm trying to express? I'm using Typescript 4.5.2 and my tsconfig.json
is as follows:
{
"compilerOptions": {
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"noImplicitOverride": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"strict": true
}
}
CodePudding user response:
I would use a ReadonlyArray
.
export type Foo = { foo: string };
export class Bar {
readonly foo: Foo;
readonly bars: ReadonlyArray<Readonly<Bar>>;
constructor(
foo: Readonly<Foo>,
bars: ReadonlyArray<Readonly<Bar>>,
) {
this.foo = foo;
this.bars = bars;
}
}
In the statement readonly bars: ReadonlyArray<Readonly<Bar>>
, the meaning of the different parts is as follows:
readonly
states that thebars
property is readonly, it prevents you from writingthis.bars = whatever
.ReadonlyArray
states that the array is readonly, it prevents you from writingthis.bars[0] = whatever
.Readonly<Bar>
states that the elements of the array are readonly, it preventsthis.bars[0].foo = whatever
.