You would have to add readonly
to the type of the field arr
in Test
.
type Test = {
str: string;
arr: readonly string[];
};
Edit: given your preference to keep the Test
arr
field mutable, you could try something like this. Make arr
a union type of both string[]
and readonly string[]
.
However, you will immediately run into other issues, because if TypeScript doesn't know which type arr
has for a given instance of Test
, it will assume the most restrictive behavior and enforce that you can't actually mutate the array.
The solution is to have utility functions like pushIfNotReadonly()
below which can use type guards to ensure the given array is in fact mutable before trying to do such an operation. But the "failure" behavior is kind of undefined - maybe you just don't push the value into the array, but how do you account for that tricky behavior in your logic? You'll quickly lose track of what is happening, useful type checking goes out the window and you get yourself into a mess.
What you're trying to do just isn't very compatible with TypeScript patterns and should be avoided if you can. I recommend you rethink how you are using type definitions and what your fundamental intent is, and evaluate other options.
type Test = {
obj: object;
arr: string[] | readonly string[];
};
export const test1: Test = {
obj: {},
arr: ['foo'],
} as const;
export const test2: Test = {
obj: {},
arr: ['bar'],
}
function pushIfNotReadonly(arr: Test['arr'], value: string) {
if (Array.isArray(arr)) {
arr.push(value)
}
}
pushIfNotReadonly(test1.arr, 'string'); // will not push because it is readonly
pushIfNotReadonly(test2.arr, 'string'); // will push because it is NOT readonly