Why can't typescript infer the generic type of a conditional properly?

Viewed 103

Here's my problem:

export type ForEachList<T> =
    T extends Element ? (NodeListOf<T> | HTMLCollectionOf<T>) :
    T extends CSSRule ? CSSRuleList :
    T extends Attr ? NamedNodeMap :
    T extends Node ? (Node[] | NodeList) :
    T[];

export function forEach<T>(array: ForEachList<T>,
                        forEachFn: (value: T, index: number, arr: ForEachList<T>, done: () => void) => boolean | void,
                        thisArg?: any): void { 
    for (let i = 0; i < array.length; i++) {
        const foo = array[i];
        forEachFn.call(thisArg, foo, i, array, () => { /* empty on purpose */ });
//                              ^^^ error here
    }
}
Argument of type 'Node | CSSRule | T' is not assignable to parameter of type 'T'.
  'T' could be instantiated with an arbitrary type which could be unrelated to 'Node | CSSRule | T'.
    Type 'Node' is not assignable to type 'T'.
      'T' could be instantiated with an arbitrary type which could be unrelated to 'Node'.(2345

Playground Link

Typescript shows that foo is of type T | CSSRule | Node. However, the typings for ForEachList only allow a list of single types, not a union. If I remove the conditions for CSSRule, Attr and Node, it works properly. Why is foo not of type T here?

0 Answers
Related