SimpleJ
SimpleJ

Reputation: 14778

Typescript generic array is being cast to any[]?

I'm trying to write some generic array utility functions, but when I try calling one from another, the compiler seems to cast the generic to any[] and gives me this error:

Type 'any[]' is not assignable to type 'T'.

My code:

type UnwrapArray<T extends any[]> = T extends (infer G)[] ? G : never;

function removeFromArray<T extends any[]>(
  array: T,
  value: UnwrapArray<T>
) {
  return array.filter(other => other !== value);
}

function toggleArrayValue<T extends any[]>(array: T, value: UnwrapArray<T>): T {
  if(array.includes(value)) {
    return removeFromArray<T>(array, value);
  } else {
    return [...array, value];
  }
}

The specific lines giving me trouble are these:

return removeFromArray<T>(array, value);

And

return [...array, value];

I've found I can add as T to a bunch of stuff and it will compile successfully, but it seems like the compiler should figure this out on its own.

Upvotes: 1

Views: 160

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250056

You assume T extends any[] will mean T is an array, and any new array will be assignable to T. This is not true.

Consider the following:

const myArr = Object.assign([1, 2, 3], {
    extraProp : 1
})

toggleArrayValue(myArr, 1).extraProp // ts says this should be here where is my extraProp

extends any[] is the lower bound on what T can be, but it can be anything that inherits array (or a tuple but that is another can of worms of why this can't work)

I am not sure at least from your sample code why you need T to be an array. You can express what you are trying to do without this:

function removeFromArray<T>(
    array: T[],
    value: T
) {
    return array.filter(other => other !== value);
}

function toggleArrayValue<T>(array: T[], value: T): T[] {
    if (array.includes(value)) {
        return removeFromArray<T>(array, value);
    } else {
        return [...array, value];
    }
}

Maybe your actual code is more complex, if so post that (maybe in a different question) and we can see if we can find a better solution than an unsafe type assertion.

Upvotes: 2

Related Questions