I've built a method that will concatentate an array with another array that's passed in. The array lives on a parent object called state which is generically typed in my method.
My method is along the lines of this:
export const mutateConcat = <T, K extends keyof T>(state: T, key: K, val: T[K]) => {
((state[key] as unknown) as any[]) = ((state[key] as unknown) as any[]).concat(val);
}
Obviously this is ugly, and I'd like to get rid of the casting to unknown and any[]. I'd also like to be able to determine the type of the array contents.
Basically, I need to ensure that T[K] is an Array, and ideally I'd like to assign the type of the contents of the array to another generic parameter, say U.
I have tried <T, K extends keyof T, U extends Array<T[K]>> but that assigns U to the type of the array itself, not to the type of the contents of the array.
Is what I'm asking possible? Can extends keyof be filtered to only keys that are array types, and can the types of the contents of those arrays be assigned to another type parameter?
Thanks in advance
Edit:
So, I've managed to get the type of the array by keying off of the val variable. So the following:
export const mutateConcat = <T, U, K extends keyof T>(state: T, key: K, val: T[K] & U[], arrayDistinctProperty?: keyof U) => {
// U now contains the array type, and `arrayDistinctProperty` is typed to a property on that array type object
((state[key] as unknown) as any[]) = ((state[key] as unknown) as any[]).concat(val);
}
However, this doesn't solve the ugliness of the casting, because typescript doesn't know for sure that T[K] is an array type. Is it possible to tell it to only allow my key parameter to be an array type on T?