diff --git a/baselines/dom.generated.d.ts b/baselines/dom.generated.d.ts index a6556cb39..3e805338f 100644 --- a/baselines/dom.generated.d.ts +++ b/baselines/dom.generated.d.ts @@ -14051,9 +14051,12 @@ interface Element extends Node, ARIAMixin, Animatable, ChildNode, NonDocumentTyp * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/matches) */ - matches(selectors: K): this is HTMLElementTagNameMap[K]; - matches(selectors: K): this is SVGElementTagNameMap[K]; - matches(selectors: K): this is MathMLElementTagNameMap[K]; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches(selectors: K): boolean; + matches(selectors: K): boolean; + matches(selectors: K): boolean; matches(selectors: string): boolean; /** * The **`releasePointerCapture()`** method of the Element interface releases (stops) pointer capture that was previously set for a specific (PointerEvent) pointer. @@ -43880,6 +43883,8 @@ interface MathMLElementTagNameMap { "semantics": MathMLElement; } +type ElementMatchesMap = { [K in keyof T as T[K] extends U ? U extends T[K] ? never : K : never]: T[K] }; + /** @deprecated Directly use HTMLElementTagNameMap or SVGElementTagNameMap as appropriate, instead. */ type ElementTagNameMap = HTMLElementTagNameMap & Pick>; diff --git a/baselines/ts5.5/dom.generated.d.ts b/baselines/ts5.5/dom.generated.d.ts index e1e2ad25d..a962e6705 100644 --- a/baselines/ts5.5/dom.generated.d.ts +++ b/baselines/ts5.5/dom.generated.d.ts @@ -14038,9 +14038,12 @@ interface Element extends Node, ARIAMixin, Animatable, ChildNode, NonDocumentTyp * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/matches) */ - matches(selectors: K): this is HTMLElementTagNameMap[K]; - matches(selectors: K): this is SVGElementTagNameMap[K]; - matches(selectors: K): this is MathMLElementTagNameMap[K]; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches(selectors: K): boolean; + matches(selectors: K): boolean; + matches(selectors: K): boolean; matches(selectors: string): boolean; /** * The **`releasePointerCapture()`** method of the Element interface releases (stops) pointer capture that was previously set for a specific (PointerEvent) pointer. @@ -43854,6 +43857,8 @@ interface MathMLElementTagNameMap { "semantics": MathMLElement; } +type ElementMatchesMap = { [K in keyof T as T[K] extends U ? U extends T[K] ? never : K : never]: T[K] }; + /** @deprecated Directly use HTMLElementTagNameMap or SVGElementTagNameMap as appropriate, instead. */ type ElementTagNameMap = HTMLElementTagNameMap & Pick>; diff --git a/baselines/ts5.6/dom.generated.d.ts b/baselines/ts5.6/dom.generated.d.ts index be2edd668..a7f3ee97d 100644 --- a/baselines/ts5.6/dom.generated.d.ts +++ b/baselines/ts5.6/dom.generated.d.ts @@ -14048,9 +14048,12 @@ interface Element extends Node, ARIAMixin, Animatable, ChildNode, NonDocumentTyp * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/matches) */ - matches(selectors: K): this is HTMLElementTagNameMap[K]; - matches(selectors: K): this is SVGElementTagNameMap[K]; - matches(selectors: K): this is MathMLElementTagNameMap[K]; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches(selectors: K): boolean; + matches(selectors: K): boolean; + matches(selectors: K): boolean; matches(selectors: string): boolean; /** * The **`releasePointerCapture()`** method of the Element interface releases (stops) pointer capture that was previously set for a specific (PointerEvent) pointer. @@ -43877,6 +43880,8 @@ interface MathMLElementTagNameMap { "semantics": MathMLElement; } +type ElementMatchesMap = { [K in keyof T as T[K] extends U ? U extends T[K] ? never : K : never]: T[K] }; + /** @deprecated Directly use HTMLElementTagNameMap or SVGElementTagNameMap as appropriate, instead. */ type ElementTagNameMap = HTMLElementTagNameMap & Pick>; diff --git a/baselines/ts5.9/dom.generated.d.ts b/baselines/ts5.9/dom.generated.d.ts index 24a34aa36..7ffeb235f 100644 --- a/baselines/ts5.9/dom.generated.d.ts +++ b/baselines/ts5.9/dom.generated.d.ts @@ -14048,9 +14048,12 @@ interface Element extends Node, ARIAMixin, Animatable, ChildNode, NonDocumentTyp * * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Element/matches) */ - matches(selectors: K): this is HTMLElementTagNameMap[K]; - matches(selectors: K): this is SVGElementTagNameMap[K]; - matches(selectors: K): this is MathMLElementTagNameMap[K]; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches>(selectors: K): this is Extract; + matches(selectors: K): boolean; + matches(selectors: K): boolean; + matches(selectors: K): boolean; matches(selectors: string): boolean; /** * The **`releasePointerCapture()`** method of the Element interface releases (stops) pointer capture that was previously set for a specific (PointerEvent) pointer. @@ -43877,6 +43880,8 @@ interface MathMLElementTagNameMap { "semantics": MathMLElement; } +type ElementMatchesMap = { [K in keyof T as T[K] extends U ? U extends T[K] ? never : K : never]: T[K] }; + /** @deprecated Directly use HTMLElementTagNameMap or SVGElementTagNameMap as appropriate, instead. */ type ElementTagNameMap = HTMLElementTagNameMap & Pick>; diff --git a/src/build/emitter.ts b/src/build/emitter.ts index a05c088b3..af9dd16c0 100644 --- a/src/build/emitter.ts +++ b/src/build/emitter.ts @@ -645,7 +645,12 @@ export function emitWebIdl( const paramName = m.signature[0].param![0].name; for (const mapName of tagNameMapNames) { printer.printLine( - `matches(${paramName}: K): this is ${mapName}[K];`, + `matches>(${paramName}: K): this is Extract<${mapName}[K], this>;`, + ); + } + for (const mapName of tagNameMapNames) { + printer.printLine( + `matches(${paramName}: K): boolean;`, ); } printer.printLine(`matches(${paramName}: string): boolean;`); @@ -715,6 +720,13 @@ export function emitWebIdl( printer.printLine(""); } + function emitElementMatchesMap() { + printer.printLine( + "type ElementMatchesMap = { [K in keyof T as T[K] extends U ? U extends T[K] ? never : K : never]: T[K] };", + ); + printer.printLine(""); + } + /// Emit overloads for the createEvent method function emitCreateEventOverloads(m: Browser.Method) { if (matchParamMethodSignature(m, "createEvent", "Event", "string")) { @@ -1664,6 +1676,7 @@ export function emitWebIdl( "MathMLElementTagNameMap", tagNameToEleName.mathMLResult, ); + emitElementMatchesMap(); emitDeprecatedHTMLOrSVGElementTagNameMap(); emitNamedConstructors(); } diff --git a/unittests/files/matches.ts b/unittests/files/matches.ts new file mode 100644 index 000000000..d9c6346e5 --- /dev/null +++ b/unittests/files/matches.ts @@ -0,0 +1,19 @@ +declare const element: Element; +declare const htmlElement: HTMLElement; +declare const htmlTableCellElement: HTMLTableCellElement; + +if (element.matches("dt")) { + const narrowed: HTMLElement = element; +} + +if (!htmlElement.matches("dt")) { + htmlElement.id; +} + +if (htmlElement.matches("td")) { + const narrowed: HTMLTableCellElement = htmlElement; +} + +if (!htmlTableCellElement.matches("th")) { + htmlTableCellElement.id; +}