如何访问含连字符的对象键?TypeScript报错问题排查
fill-color属性报错 问题场景
你有如下对象:
{ "type": "fill", "id": "asdf", "paint": { "fill-color": "#440d0d" } }
尝试通过以下代码获取fill-color属性:
if (mapStyle["paint"]){ const fillColor = mapStyle['paint']["fill-color"] }
但遇到TypeScript错误:
Element implicitly has an 'any' type because expression of type '"fill-color"' can't be used to index type '{ "fill-antialias"?: PropertyValueSpecification
| undefined; "fill-opacity"?: DataDrivenPropertyValueSpecification | undefined; ... 4 more ...; "fill-pattern"?: DataDrivenPropertyValueSpecification<...> | undefined; } | ... 7 more ... | { ...; }'.
Property 'fill-color' does not exist on type '{ "fill-antialias"?: PropertyValueSpecification| undefined; "fill-opacity"?: DataDrivenPropertyValueSpecification | undefined; ... 4 more ...; "fill-pattern"?: DataDrivenPropertyValueSpecification<...> | undefined; } | ... 7 more ... | { ...; }'.ts(7053)
(property) "paint"?: {
"fill-antialias"?: PropertyValueSpecification| undefined;
"fill-opacity"?: DataDrivenPropertyValueSpecification| undefined;
... 4 more ...;
"fill-pattern"?: DataDrivenPropertyValueSpecification<...> | undefined;
} | ... 8 more ... | undefined
问题原因
TypeScript推断mapStyle.paint的类型是多种图层paint配置的联合类型,其中不仅包含fill类型的paint配置,还包含line、circle等其他7-8种图层类型的paint配置。这些非fill类型的paint配置里并没有fill-color属性,因此当你用"fill-color"去索引这个联合类型时,TypeScript无法确定当前paint属于哪一种具体类型,会判定这个访问不安全,从而抛出错误。
简言之:你明确知道当前mapStyle是fill类型,但TypeScript仅知道paint可能是任意一种图层的配置,只有fill类型的paint才有fill-color,所以不允许直接访问。
解决方法
1. 用类型守卫缩小类型范围
通过检查mapStyle.type确认是fill类型,TypeScript会自动将paint的类型缩小为fill专属的配置类型:
if (mapStyle.type === 'fill' && mapStyle.paint) { const fillColor = mapStyle.paint["fill-color"]; // 此时无类型报错 }
2. 类型断言(仅在确定类型时使用)
如果你能100%保证当前mapStyle是fill类型,可以用类型断言强制指定paint的类型:
if (mapStyle.paint) { // 直接断言为包含fill-color的类型 const fillColor = (mapStyle.paint as { "fill-color"?: string })["fill-color"]; // 或者使用地图库提供的官方类型(比如Mapbox/MapLibre的FillPaint) // import { FillPaint } from 'maplibre-gl' // const fillColor = (mapStyle.paint as FillPaint)["fill-color"]; }
3. 定义精确的自定义类型
如果你的场景中mapStyle只能是fill类型,直接给它定义更精确的类型:
interface FillMapStyle { type: "fill"; id: string; paint?: { "fill-color"?: string; // 按需添加其他fill类型的paint属性 }; } // 给mapStyle指定精确类型 const mapStyle: FillMapStyle = { "type": "fill", "id": "asdf", "paint": { "fill-color": "#440d0d" } }; if (mapStyle.paint) { const fillColor = mapStyle.paint["fill-color"]; // 无报错 }
内容的提问来源于stack exchange,提问作者pcace

