Skip to content

Commit 34507a8

Browse files
authored
h: type check attributes object (microsoft#155501)
1 parent 39fdb27 commit 34507a8

File tree

2 files changed

+29
-38
lines changed

2 files changed

+29
-38
lines changed

src/vs/base/browser/dom.ts

Lines changed: 28 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1734,18 +1734,27 @@ export function computeClippingRect(elementOrRect: HTMLElement | DOMRectReadOnly
17341734
return { top, right, bottom, left };
17351735
}
17361736

1737-
interface DomNodeAttributes {
1738-
role?: string;
1739-
ariaHidden?: boolean;
1740-
style?: StyleAttributes;
1741-
}
1742-
1743-
interface StyleAttributes {
1744-
height?: number | string;
1745-
width?: number | string;
1746-
}
1737+
type HTMLElementAttributeKeys<T> = Partial<{ [K in keyof T]: T[K] extends Function ? never : T[K] extends object ? HTMLElementAttributeKeys<T[K]> : T[K] }>;
1738+
type ElementAttributes<T> = HTMLElementAttributeKeys<T> & Record<string, any>;
1739+
type RemoveHTMLElement<T> = T extends HTMLElement ? never : T;
1740+
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
1741+
type ArrayToObj<T extends any[]> = UnionToIntersection<RemoveHTMLElement<T[number]>>;
17471742

1748-
//<div role="presentation" aria-hidden="true" class="scroll-decoration"></div>
1743+
type TagToElement<T> = T extends `.${string}`
1744+
? HTMLDivElement
1745+
: T extends `#${string}`
1746+
? HTMLDivElement
1747+
: T extends `${infer TStart}#${string}`
1748+
? TStart extends keyof HTMLElementTagNameMap
1749+
? HTMLElementTagNameMap[TStart]
1750+
: HTMLElement
1751+
: T extends `${infer TStart}.${string}`
1752+
? TStart extends keyof HTMLElementTagNameMap
1753+
? HTMLElementTagNameMap[TStart]
1754+
: HTMLElement
1755+
: T extends keyof HTMLElementTagNameMap
1756+
? HTMLElementTagNameMap[T]
1757+
: HTMLElement;
17491758

17501759
/**
17511760
* A helper function to create nested dom nodes.
@@ -1762,22 +1771,25 @@ interface StyleAttributes {
17621771
* private readonly editor = createEditor(this.htmlElements.editor);
17631772
* ```
17641773
*/
1774+
export function h<TTag extends string>(
1775+
tag: TTag
1776+
): (Record<'root', TagToElement<TTag>>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;
17651777
export function h<TTag extends string, TId extends string>(
17661778
tag: TTag,
1767-
attributes: { $: TId } & DomNodeAttributes
1779+
attributes: { $: TId } & Partial<ElementAttributes<TagToElement<TTag>>>
17681780
): Record<TId | 'root', TagToElement<TTag>>;
1769-
export function h<TTag extends string>(tag: TTag, attributes: DomNodeAttributes): Record<'root', TagToElement<TTag>>;
17701781
export function h<TTag extends string, T extends (HTMLElement | string | Record<string, HTMLElement>)[]>(
17711782
tag: TTag,
17721783
children: T
17731784
): (ArrayToObj<T> & Record<'root', TagToElement<TTag>>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;
1785+
export function h<TTag extends string>(tag: TTag, attributes: Partial<ElementAttributes<TagToElement<TTag>>>): Record<'root', TagToElement<TTag>>;
17741786
export function h<TTag extends string, TId extends string, T extends (HTMLElement | string | Record<string, HTMLElement>)[]>(
17751787
tag: TTag,
1776-
attributes: { $: TId } & DomNodeAttributes,
1788+
attributes: { $: TId } & Partial<ElementAttributes<TagToElement<TTag>>>,
17771789
children: T
17781790
): (ArrayToObj<T> & Record<TId, TagToElement<TTag>>) extends infer Y ? { [TKey in keyof Y]: Y[TKey] } : never;
1779-
export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNodeAttributes | Record<string, any>, children?: any[]] | [children: any[]]): Record<string, HTMLElement> {
1780-
let attributes: { $?: string } & DomNodeAttributes;
1791+
export function h(tag: string, ...args: [] | [attributes: { $: string } & Partial<ElementAttributes<HTMLElement>> | Record<string, any>, children?: any[]] | [children: any[]]): Record<string, HTMLElement> {
1792+
let attributes: { $?: string } & Partial<ElementAttributes<HTMLElement>>;
17811793
let children: (Record<string, HTMLElement> | HTMLElement)[] | undefined;
17821794

17831795
if (Array.isArray(args[0])) {
@@ -1845,24 +1857,3 @@ export function h(tag: string, ...args: [] | [attributes: { $: string } & DomNod
18451857
function camelCaseToHyphenCase(str: string) {
18461858
return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
18471859
}
1848-
1849-
type RemoveHTMLElement<T> = T extends HTMLElement ? never : T;
1850-
1851-
type ArrayToObj<T extends any[]> = UnionToIntersection<RemoveHTMLElement<T[number]>>;
1852-
1853-
1854-
type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends ((k: infer I) => void) ? I : never;
1855-
1856-
type HTMLElementsByTagName = {
1857-
div: HTMLDivElement;
1858-
span: HTMLSpanElement;
1859-
a: HTMLAnchorElement;
1860-
};
1861-
1862-
type TagToElement<T> = T extends `${infer TStart}.${string}`
1863-
? TStart extends keyof HTMLElementsByTagName
1864-
? HTMLElementsByTagName[TStart]
1865-
: HTMLElement
1866-
: T extends keyof HTMLElementsByTagName
1867-
? HTMLElementsByTagName[T]
1868-
: HTMLElement;

src/vs/workbench/contrib/mergeEditor/browser/view/editorGutter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class EditorGutter<T extends IGutterItemInfo = IGutterItemInfo> extends D
3131
super();
3232
this._domNode.className = 'gutter monaco-editor';
3333
const scrollDecoration = this._domNode.appendChild(
34-
h('div.scroll-decoration', { role: 'presentation', ariaHidden: true, style: { width: '100%' } })
34+
h('div.scroll-decoration', { role: 'presentation', ariaHidden: 'true', style: { width: '100%' } })
3535
.root
3636
);
3737

0 commit comments

Comments
 (0)