Argument of type 'readonly …' is not assignable to parameter of type '…[]'

Issue

There’s a similar question but it’s a different problem from mine found here Argument of type '…' is not assignable to parameter of type '…' TS 2345

utils.ts (https://www.typescriptlang.org/docs/handbook/2/generics.html#generic-types)

export function getRandomItem<T>(array: T[]): T {
  return array[Math.floor(Math.random() * array.length)]
}

apparel.ts

import { getRandomItem } from "@/assets/ts/utils"

export const apparelLocation = ["HEAD", "TORSO", "ARMS", "LEGS"] as const
export type TypeApparelLocation = typeof apparelLocation[number]

// ...

export class Apparel {
  / ...
  location: TypeApparelLocation

  constructor(rating: number) {
    // ...
    this.location = getRandomItem(apparelLocation)
    }
  }

Will give an error inside when using the getRandomItem()

Argument of type 'readonly ["HEAD", "TORSO", "ARMS", "LEGS"]' is not assignable to parameter of type '("HEAD" | "TORSO" | "ARMS" | "LEGS")[]'. The type 'readonly ["HEAD", "TORSO", "ARMS", "LEGS"]' is 'readonly' and cannot be assigned to the mutable type '("HEAD" | "TORSO" | "ARMS" | "LEGS")[]'.ts(2345)

What I’m trying to do (in case needed for a better understanding):

  1. create a variable containing an array with literal values
  2. create a type declaration (an union of literal) from that array (TypeScript: Define a union type from an array of strings)
  3. use that type as an annotation on a class attribute
  4. select a random element from the array to assign to the location attribute

As to why I need the first reason is because I need do a loop somewhere else.

Few "fixes" I found:

  1. removing as const from the apparelLocation made it work but I can assign any value to location and not just those 4
  2. removing type annotation on the function and use a plain array: any also works but it’s giving a warning

Apologies if it’s an obvious mistake by me since I’m relatively new to typescript.

Solution

Unless someone proves me wrong, what I understood is that typescript is complaining that you’re passing an immutable array to the function, because the function parameter array is mutable and can be edited, while the value you’re passing is a constant.

The better solution is to setup the function paramater as readonly:

function getRandomItem<T>(array: readonly T[]): T {
   // ...
}

By setting the parameter as readonly, typescript won’t complain anymore because you won’t be able to modify it inside the function.

Another, less nice, solution could be editing the call like this:

this.location = getRandomItem([...apparelLocation])

This way, you’re not passing the original, immutable array, but just a copy of it that can be handled and is coherent with the function parameter being mutable.

Answered By – Drago96

Answer Checked By – Clifford M. (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.