diff --git a/packages/visualizations/src/components/Map/utils.ts b/packages/visualizations/src/components/Map/utils.ts index 5b8850b2..faef7126 100644 --- a/packages/visualizations/src/components/Map/utils.ts +++ b/packages/visualizations/src/components/Map/utils.ts @@ -6,8 +6,14 @@ import type { Feature, FeatureCollection, Position, BBox } from 'geojson'; import type { Scale } from 'chroma-js'; import { DEFAULT_COLORS } from './constants'; import { assertUnreachable } from '../utils'; -import { ColorScaleTypes } from '../types'; -import type { Color, ColorScale, DataBounds } from '../types'; +import { + Color, + ColorScale, + DataBounds, + isGroupByForMatchExpression, + ColorScaleTypes, +} from '../types'; + import type { ChoroplethDataValue, ChoroplethFixedTooltipDescription, @@ -296,9 +302,8 @@ export const computeMatchExpression = ( const groupByColors: ExpressionInputType[] = []; Object.entries(colors).forEach((e) => groupByColors.push(...e)); groupByColors.push(emptyValueColor); // Default fallback color - // We constructed a match expression so we can cast here the final type - return [ - ...matchExpression, - ...(groupByColors as [ExpressionInputType, ExpressionInputType, ExpressionInputType]), - ]; + if (!isGroupByForMatchExpression(groupByColors)) { + throw new Error('Not the expected type for complete match expression'); + } + return [...matchExpression, ...groupByColors]; }; diff --git a/packages/visualizations/src/components/MapPoi/utils.ts b/packages/visualizations/src/components/MapPoi/utils.ts index ec5c6329..2c133bd5 100644 --- a/packages/visualizations/src/components/MapPoi/utils.ts +++ b/packages/visualizations/src/components/MapPoi/utils.ts @@ -6,7 +6,7 @@ import type { ExpressionInputType, } from 'maplibre-gl'; -import type { Color } from '../types'; +import { isGroupByForMatchExpression, type Color } from '../types'; import type { CenterZoomOptions, @@ -55,13 +55,12 @@ export const getMapLayers = (layers?: Layer[]): CircleLayerSpecification[] => { groupByColors.push(color, colors[color]); }); groupByColors.push(layerColor); + if (!isGroupByForMatchExpression(groupByColors)) { + throw new Error('Not the expected type for complete match expression'); + } circleColor = [ ...matchExpression, - ...(groupByColors as [ - ExpressionInputType, - ExpressionInputType, - ExpressionInputType - ]), + ...groupByColors, ]; if (borderColors) { @@ -74,14 +73,12 @@ export const getMapLayers = (layers?: Layer[]): CircleLayerSpecification[] => { groupByBorderColors.push(borderColor, borderColors[borderColor]); }); groupByBorderColors.push(circleBorderColor || DEFAULT_DARK_GREY); - // We constructed a match expression so we can cast here the final type + if (!isGroupByForMatchExpression(groupByBorderColors)) { + throw new Error('Not the expected type for complete match expression'); + } circleBorderColor = [ ...matchBorderExpression, - ...(groupByBorderColors as [ - ExpressionInputType, - ExpressionInputType, - ExpressionInputType - ]), + ...groupByBorderColors, ]; } } diff --git a/packages/visualizations/src/components/types.ts b/packages/visualizations/src/components/types.ts index c6f87b1d..2e1f0cfc 100644 --- a/packages/visualizations/src/components/types.ts +++ b/packages/visualizations/src/components/types.ts @@ -1,3 +1,5 @@ +import type { ExpressionInputType } from 'maplibre-gl'; + // eslint-disable-next-line @typescript-eslint/no-explicit-any export type DataFrame = Record[]; @@ -33,3 +35,10 @@ export type PaletteScale = { }; export type ColorScale = GradientScale | PaletteScale; + +// We expect an array with couples of values and ExpressionInput and for the last element a default ExpressionInput +export function isGroupByForMatchExpression( + value: ExpressionInputType[] +): value is [ExpressionInputType, ExpressionInputType, ExpressionInputType] { + return value.length >= 3 && value.length % 2 === 1; +}