TypeScript过滤空对象及Mapbox-GL坐标非空渲染问题求助
我来帮你解决这个问题!你遇到的核心问题是没有在渲染前就过滤掉坐标无效的项,反而先尝试处理空值导致了空对象和类型错误。咱们一步步来修复:
第一步:从源头过滤无效坐标,避免空对象问题
你现在的做法是先遍历所有系统再处理空值,但这样即使坐标无效,还是会返回SystemMarker组件,导致访问空对象属性的错误。正确的思路是先过滤掉那些last_position里lon或lat为null/undefined的系统,这样无效项根本不会进入渲染流程:
<Cluster ClusterMarkerFactory={clusterMarker} zoomOnClick> {systems // 先过滤:只保留有有效经纬度的系统 .filter(({ last_position }) => { return last_position != null && last_position.lon != null && last_position.lat != null; }) .map(({ last_position, id }) => { // 这里的last_position已经确保有合法的lon和lat,直接使用即可 return ( <SystemMarker key={id} coordinates={[last_position.lon, last_position.lat]} heading={0} id={id} onClick={onSystemSelect} /> ); })} </Cluster>
这样不仅解决了类型错误,还从根本上避免了无效标记被渲染到聚类组件中。
第二步:用TypeScript类型守卫强化类型安全
如果需要更严谨的类型检查(比如让TypeScript自动推断过滤后的数据类型),可以定义一个类型守卫函数,明确判断对象是否包含有效的经纬度:
// 先定义合法坐标的类型 interface ValidPosition { lon: number; lat: number; } // 类型守卫:判断对象是否符合ValidPosition类型 function isValidPosition(position: unknown): position is ValidPosition { if (typeof position !== 'object' || position == null) { return false; } const pos = position as ValidPosition; // 确保lon和lat都是数字类型 return typeof pos.lon === 'number' && typeof pos.lat === 'number'; }
然后在过滤时使用这个守卫:
<Cluster ClusterMarkerFactory={clusterMarker} zoomOnClick> {systems .filter(({ last_position }) => isValidPosition(last_position)) .map(({ last_position, id }) => { // TypeScript会自动推断last_position是ValidPosition类型,不会再报错 return ( <SystemMarker key={id} coordinates={[last_position.lon, last_position.lat]} heading={0} id={id} onClick={onSystemSelect} /> ); })} </Cluster>
为什么你之前的reduce方法不生效?
你用reduce生成空对象后,依然会把这个空对象传给SystemMarker的coordinates属性,这就导致了filteredPositions.lon的类型错误——空对象{}确实没有lon属性。而且聚类组件还是会渲染这个无效标记,生成空的聚类点。所以从源头过滤才是最高效的解决方案。
额外:TypeScript中过滤空对象的通用方法
如果以后需要过滤像{}这样没有任何属性的空对象,可以用这个工具函数:
function isNotEmptyObject(obj: unknown): obj is Record<string, unknown> { return typeof obj === 'object' && obj != null && Object.keys(obj).length > 0; } // 使用示例: const nonEmptyObjects = someArray.filter(isNotEmptyObject);
不过回到你的场景,这个方法其实不需要,因为我们已经提前过滤了无效坐标的项,不会产生空对象。
内容的提问来源于stack exchange,提问作者Nella
相关产品推荐
相关产品推荐

