diff --git a/src/components/leaflet-image-overlay.ts b/src/components/leaflet-image-overlay.ts index 4b7bb66..f50fd79 100644 --- a/src/components/leaflet-image-overlay.ts +++ b/src/components/leaflet-image-overlay.ts @@ -1,4 +1,5 @@ import { ImageOverlay, LatLngBounds, LatLngExpression } from 'leaflet'; +import type { ImageOverlayOptions } from 'leaflet'; import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; @@ -27,7 +28,7 @@ export class LeafletImageOverlay extends withProps(HTMLElement, PROPS) { this.#obj = new ImageOverlay( url, parseBoundsAttr(this), - buildOptions(this, PROPS, ['url', 'bounds']), + buildOptions(this, PROPS, ['url', 'bounds']) as ImageOverlayOptions, ); registerChildren(this, this.#obj); } diff --git a/src/components/leaflet-svg-overlay.ts b/src/components/leaflet-svg-overlay.ts index b760e7b..5d00aa7 100644 --- a/src/components/leaflet-svg-overlay.ts +++ b/src/components/leaflet-svg-overlay.ts @@ -1,4 +1,5 @@ import { SVGOverlay, LatLngBounds, LatLngExpression } from 'leaflet'; +import type { ImageOverlayOptions } from 'leaflet'; import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; @@ -25,7 +26,7 @@ export class LeafletSVGOverlay extends withProps(HTMLElement, PROPS) { this.#obj = new SVGOverlay( svg ?? dummy!, parseBoundsAttr(this), - buildOptions(this, PROPS, ['bounds']), + buildOptions(this, PROPS, ['bounds']) as ImageOverlayOptions, ); registerChildren(this, this.#obj); } diff --git a/src/components/leaflet-tile-layer-wms.ts b/src/components/leaflet-tile-layer-wms.ts index bd2ef40..ef4b99c 100644 --- a/src/components/leaflet-tile-layer-wms.ts +++ b/src/components/leaflet-tile-layer-wms.ts @@ -24,7 +24,7 @@ export class LeafletTileLayerWMS extends withProps(HTMLElement, PROPS) { const url = this.getAttribute('url') || ''; this.#obj = new TileLayer.WMS( url, - buildOptions(this, PROPS, ['url']) as Record, + buildOptions(this, PROPS, ['url']), ); registerChildren(this, this.#obj); } diff --git a/src/components/leaflet-tooltip.ts b/src/components/leaflet-tooltip.ts index cb0720c..8d4c85a 100644 --- a/src/components/leaflet-tooltip.ts +++ b/src/components/leaflet-tooltip.ts @@ -1,4 +1,5 @@ import { Tooltip } from 'leaflet'; +import type { TooltipOptions } from 'leaflet'; import { registerWithParent, buildOptions, numAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; @@ -23,7 +24,7 @@ export class LeafletTooltip extends withProps(HTMLElement, PROPS) { this.#obj = new Tooltip({ ...buildOptions(this, PROPS, ['lat', 'lng']), content: this.innerHTML, - }); + } as unknown as TooltipOptions); if (this.hasAttribute('lat') && this.hasAttribute('lng')) { this.#obj.setLatLng([numAttr(this, PROPS, 'lat'), numAttr(this, PROPS, 'lng')]); } diff --git a/src/components/leaflet-video-overlay.ts b/src/components/leaflet-video-overlay.ts index 62ffa1c..26a4468 100644 --- a/src/components/leaflet-video-overlay.ts +++ b/src/components/leaflet-video-overlay.ts @@ -1,4 +1,5 @@ import { VideoOverlay, LatLngBounds, LatLngExpression } from 'leaflet'; +import type { VideoOverlayOptions } from 'leaflet'; import { buildOptions, buildAttrMap, setLayerAttr, parseBoundsAttr } from '../core/utils.js'; import { withProps } from '../core/with-props.js'; @@ -28,7 +29,7 @@ export class LeafletVideoOverlay extends withProps(HTMLElement, PROPS) { this.#obj = new VideoOverlay( url, parseBoundsAttr(this), - buildOptions(this, PROPS, ['url', 'bounds']), + buildOptions(this, PROPS, ['url', 'bounds']) as VideoOverlayOptions, ); registerChildren(this, this.#obj); } diff --git a/src/core/utils.ts b/src/core/utils.ts index 718f43d..9d81fa2 100644 --- a/src/core/utils.ts +++ b/src/core/utils.ts @@ -1,4 +1,4 @@ -import type { PropDef } from '../types/props.js'; +import type { PropDef, PropTypesFromTable } from '../types/props.js'; import type { LatLngBoundsExpression } from 'leaflet'; // Converts kebab-case to camelCase (e.g. "fill-color" → "fillColor"). @@ -108,12 +108,20 @@ export function setLayerAttr( // constructors, like coordinates or URLs). Null attributes use the // default from PROPS if one exists (skipping empty-string defaults to // avoid Leaflet rejecting them). -export function buildOptions( +// +// The return type is derived from the PROPS table: each prop name maps +// to its kind's value type (number for `num`, boolean for `bool-on`/`bool-off`, +// string for `str`). The `const` type parameter makes literal exclude arrays +// narrow correctly so excluded keys are stripped from the return type. +export function buildOptions< + TProps extends Record, + const TExclude extends readonly string[] = [], +>( el: HTMLElement, - props: Record, - exclude: string[] = [], -): Record { - const opts: Record = {}; + props: TProps, + exclude: TExclude = [] as unknown as TExclude, +): Omit, TExclude[number]> { + const opts = {} as Record; for (const [propName, spec] of Object.entries(props)) { if (exclude.includes(propName)) continue; const val = el.getAttribute(spec.attr); @@ -126,7 +134,7 @@ export function buildOptions( else if (spec.kind === 'bool-off') opts[propName] = false; else opts[propName] = val; } - return opts; + return opts as Omit, TExclude[number]>; } // Dispatches a custom `leaflet-register` event upward through the DOM