Skip to content

indexing with T extends keyof <Large Union> causes OOM if keyof has a number #24223

Closed
@weswigham

Description

@weswigham

Ref #23977 and discussion on #24137

Code

Isolated repro (needs dom lib for ElementTagNameMap and associated types):

// @strict: true
// Modified repro from #23977

declare global {
    interface ElementTagNameMap {
        [index: number]: HTMLElement
    }

    interface HTMLElement {
        [index: number]: HTMLElement;
    }
}

export function assertIsElement(node: Node | null): node is Element {
    let nodeType = node === null ? null : node.nodeType;
    return nodeType === 1;
}
  
export function assertNodeTagName<
    T extends keyof ElementTagNameMap,
    U extends ElementTagNameMap[T]>(node: Node | null, tagName: T): node is U {
    if (assertIsElement(node)) {
        const nodeTagName = node.tagName.toLowerCase();
         return nodeTagName === tagName;
    }
    return false;
}
  
export function assertNodeProperty<
    T extends keyof ElementTagNameMap,
    P extends keyof ElementTagNameMap[T],
    V extends HTMLElementTagNameMap[T][P]>(node: Node | null, tagName: T, prop: P, value: V) {
    if (assertNodeTagName(node, tagName)) {
        node[prop];
    }
}

Expected behavior:
No crash.

Actual behavior:
OOM crash after a very long delay.

Preliminary investigation shows the OOM occurs when we try to get the distributed form of keyof <Large Union> - namely the process is defined recursively, so when the union has ~170 members, we create 170 intermediate types (flattening one member at a time, while also wasting time recalculating type flags and other bits we will never need) before getting the final, distributed result. Now, picture doing this on every relation comparison operation for P (this distribution is uncached), and multiplying it for V in assertNodeProperty - the complexity is huge. Our fast path doesn't fix this, since the numeric index signatures cause us to bail on the fast path as it currently is.

Metadata

Metadata

Assignees

Labels

BugA bug in TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions