0

Description: I'm trying to update my useState, newCase, with property values coming from a form.

Problem: Assigning the value results in the error: Type 'string' is not assignable to type 'never', and I don't know how to fix it.

Here's the interface of a case object:

  export interface ICases {
  materials: Material[]
  finalActivity: boolean
  existingCase: boolean
  timestamp: Timestamp
  description: string
  userId: string
  caseName: string
  geoLocation: string
  done: boolean
  id: string
  parentActivityID: string
  first: boolean
}

And here is the relevant code to the AddCase modal.

const [newCase, setNewCase] = useState<ICases>()

  const updateCase = (key: keyof ICases, value: string) => {
    const updatedCase = newCase ? { ...newCase } : ({} as ICases)
    updatedCase[key] = value
    setNewCase(updatedCase)
  }
asportnoy
  • 2,218
  • 2
  • 17
  • 31
Alula48
  • 37
  • 6

2 Answers2

1

Your issue is that the key in keyof does not necessarily have a value that's a string. To fix this, we can get just the keys that have a string value.

// https://stackoverflow.com/a/54520829/6911703
type KeysMatching<T, V> = {[K in keyof T]-?: T[K] extends V ? K : never}[keyof T];

const updateCase = (key: KeysMatching<ICases, string>, value: string) => {
  const updatedCase = newCase ? { ...newCase } : ({} as ICases)
  updatedCase[key] = value
  setNewCase(updatedCase)
}

Or, if you want value to match the type of the key, you can do this:

const updateCase = <K extends keyof ICases>(key: K, value: ICases[K]) => {
  const updatedCase = newCase ? { ...newCase } : ({} as ICases)
  updatedCase[key] = value
  setNewCase(updatedCase)
}
asportnoy
  • 2,218
  • 2
  • 17
  • 31
-1

The error is occurring because you are trying to assign a string value to a property of type Material[], Timestamp, boolean, or number which is not possible. To resolve the issue, you need to cast the value parameter to the correct type before assigning it to the updatedCase object. For example, you could use a switch statement to determine the correct type based on the key parameter:

const updateCase = (key: keyof ICases, value: string) => {
    const updatedCase = newCase ? { ...newCase } : ({} as ICases)
    switch (key) {
        case 'materials':
            updatedCase.materials = value as Material[]
            break
        case 'finalActivity':
            updatedCase.finalActivity = value === 'true'
            break
        case 'existingCase':
            updatedCase.existingCase = value === 'true'
            break
        case 'timestamp':
            updatedCase.timestamp = value as Timestamp
            break
        case 'done':
            updatedCase.done = value === 'true'
            break
        default:
            updatedCase[key] = value
    }
    setNewCase(updatedCase)
}

Note: This is just one way to resolve the issue. Depending on your specific use case, you may need to handle the casting in a different way.

Martin Seeler
  • 6,874
  • 3
  • 33
  • 45
  • You're asserting non-string values as string values. That means that either you'll be assigning a string value to something that's not meant to be a string, or you get an error when trying to use the function with the correct value type. – asportnoy Feb 12 '23 at 05:36