Open stepankuzmin opened 5 months ago
Some learnings from my migration:
@types/geojson
to keep types like GeoJSON.FeatureCollection['features']
workingflystart
or flyend
) need to be casted when binding them: mapRef.current.on('flystart' as mapboxgl.MapEvent, () => {})
In the code below I'm getting a TS error for the base
key. Any pointers how to fix or refactor that?
Object literal may only specify known properties, and 'base' does not exist in type 'ExpressionSpecification | { type: "exponential"; stops: [number, number][]; } | { type: "interval"; stops: [number, number][]; } | { type: "exponential"; stops: [...][]; property: string; default?: number | undefined; } | ... 5 more ... | { ...; }'.ts(2353)
mapRef.current?.addLayer({
id: 'unclustered-point',
type: 'circle',
source: SOURCE_ID,
filter: ['!', ['has', 'point_count']],
paint: {
'circle-radius': {
base: 1.5, // <-- TS error here
stops: [
[4, 8],
[10, 16],
],
},
'circle-color': circleColor,
},
});
Hi @slavanga,
Thanks for sharing your learnings! The error in your case is caused by using the deprecated zoom function syntax. While the older syntax is still supported, the type we use for data-driven expressions doesn’t include it. You can refer to this comparison as an example of migrating to the newer syntax:
Function | Expression |
---|---|
// make circles larger as the user // zooms from z12 to z22 'circle-radius': { 'base': 1.75, 'stops': [[12, 2], [22, 180]] }, |
// make circles larger as the user // zooms from z12 to z22 'circle-radius': [ "interpolate", ["exponential", 1.75], ["zoom"], 12, 2, 22, 180 ], |
In your case, it should be:
'circle-radius': [
'interpolate',
['exponential', 1.5],
['zoom'],
4, 8,
10, 16
]
I understand that it may not be convenient, so in the stable release, we could extend the type we provide to include the older syntax, making the migration process smoother for everyone.
@stepankuzmin Got it! Thank you for the detailed explanation. I actually think the new syntax is more clear.
Hi, I'm starting the migration to v3.5 and so far all deprecated types are easy to update, except one, which I'm having problems with:
MapboxGeoJSONFeature
has been deprecated in favor of GeoJSONFeature
, but typescript complains that it's not being exported. Any idea?
I started the migration today and it went mostly well, but I got one small issue: At one point we use CustomLayerInterface
, but this interface is not exported. As the specification for Map.addLayer
looks like this Map$1.addLayer(layer: LayerSpecification | CustomLayerInterface, beforeId?: string)
, I would assume the CustomLayerInterface
should be exported?
Similarly EasingOptions
is not exported for e.g. flyTo()
.
Some more feedback
1) MapboxGeoJSONFeature
has been deprecated in favor of GeoJSONFeature
, but the latter doesn't have the source
field. In the typings it is called QueryFeature
but that is not exported. So if you need to name it and access the source
field you have to do something fugly like
type QueryFeature = ReturnType<Map['queryRenderedFeatures']>[0];
2) GeolocateControl.on
does not support the 'trackuserlocationstart'
and 'trackuserlocationend'
events, fails with
Argument of type '"trackuserlocationstart"' is not assignable to parameter of type 'MapEvent'
Really `GeolocateControl.on` should extend `Evented.on` with the additional event types.
3) In general the map event typings are worse than the community-provided typings. You can't express that the click event has a point
field, and the idle event does not. Ok you get a star for actually having first-party typings, but pretty please have a good look at the community-provided ones for improvements.
For Angular applications that use the ever-stagnating ngx-mapbox-gl
package which provides Angular wrappers around the Mapbox types, you must now set skipLibCheck
to true
in your TypeScript config, in addition to the legacy peer deps workaround that you have had to do for a while now.
Some types are not exported, such as Marker Options, ControlPosition, EasingOptions, StyleImageInterface
const scale = new mapboxgl.ScaleControl({ maxWidth: 80 });
map.addControl(scale, controlsPosition);
Argument of type 'ScaleControl' is not assignable to parameter of type 'IControl'. Types of property '_setLanguage' are incompatible.
Thanks for the feedback. We appreciate your patience while we enhance the developer experience. We are actively working on improving TypeScript support, and the upcoming patch release will address some of the issues highlighted here. Stay tuned for updates.
three things (and some of this could be ReactMapGL
feedback):
map.on("click", (e: mapboxgl.MapMouseEvent) => {
seems like typescript should be able to tell which event string goes to which event type, so having that set up would be nice
onLoad={(e) => setMap(e.target as Map)}
a little annoying that the target is unknown
map.addLayer({
id: "containedZipCodes",
type: "fill",
source: {
~~~~~~
type: "vector",
url: "mapbox://mapbox.boundaries-pos4-v4",
},
slot: "bottom",
"source-layer": "boundaries_postal_4",
paint: getPaint(allZipCodes),
});
Type '{ type: string; url: string; }' is not assignable to type 'string'
when i change it to the string "mapbox://mapbox.boundaries-pos4-v4"
it does not work, while this object does, so i suspect the type is wrong
i'll add // @ts-expect-error -- source needs to define a vector object
while i wait for a fix for that
new mapboxgl.Popup().on('close', () => {});
Argument of type '"close"' is not assignable to parameter of type 'MapEvent'.
I get this error in node_modules\mapbox-gl\dist\mapbox-gl.d.ts
Property 'tileID' in type 'ImageSource' is not assignable to the same property in base type 'ISource'. Type 'CanonicalTileID | null | undefined' is not assignable to type 'CanonicalTileID | undefined'. Type 'null' is not assignable to type 'CanonicalTileID | undefined'.
ImageSource.titleId: CanonicalTileID | null | undefined; ISource.tileID?: CanonicalTileID;
The types in 3.5.1 are disallowing passing a number as the padding
option in map.fitBounds()
:
map.fitBounds(bounds, {
maxZoom: 12,
padding: 80,
// ~~~~~~~
// Type 'number' is not assignable to type 'PaddingOptions'. ts(2322)
// (property) padding?: PaddingOptions | undefined
});
According to the API reference this should still be supported (and my brief skim of the code confirms this)
I encountered a few types that are used for arguments on public methods but are not exported:
CustomLayerInterface
QueryFeature
FeatureSelector
Hi everyone. We've just published the GL JS v3.5.2 patch release, which includes TypeScript API improvements such as strongly typed Map event listeners, improved type narrowing, and explicit exports for some previously missed types. Please try out the new version and let us know how it works for you.
Thanks again for the feedback. I'll keep this issue open for any new findings.
I believe type CircleLayerSpecification.filter
should be type FilterSpecification | ExpressionSpecification
instead of just FilterSpecification
@stepankuzmin A couple of remaining type issues in 3.5.2
:
Map
constructor option scrollZoom
can take take a boolean
or the options object for ScrollZoomHandler.enable()
, but the type only allows for a boolean
.
Map
constructor option touchZoomRotate
can take take a boolean
or the options object for TouchZoomRotateHandler.enable()
, but the type only allows for a boolean
.
Map
constructor interaction handler options.map.addLayer({
'id': 'tower',
'type': 'model',
'source': 'model',
'layout': {
'model-id': ['get', 'model-uri']
},
'paint': {
'model-cast-shadows': true,
}
});
Type 'boolean' is not assignable to type '[string, ...any[]]'.ts(2322)
(property) "model-cast-shadows"?: ExpressionSpecification | undefined
map.addLayer({
'id': 'tower',
'type': 'model',
'source': 'model',
'layout': {
'model-id': ['get', 'model-uri']
},
'paint': {
'model-rotation': [0.0, 0.0, ['get', 'rotate']],
}
});
Type '[number, number, string[]]' is not assignable to type 'DataDrivenPropertyValueSpecification<[number, number, number]> | undefined'.
Type '[number, number, string[]]' is not assignable to type 'ExpressionSpecification | [number, number, number]'.ts(2322)
(property) "model-rotation"?: DataDrivenPropertyValueSpecification<[number, number, number]> | undefined
map.setLights([
{
"id": "directional",
"type": "directional",
"properties": {
"cast-shadows": true,
}
}
])
Type 'boolean' is not assignable to type '[string, ...any[]]'.ts(2322)
(property) "cast-shadows"?: ExpressionSpecification | undefined
Spotted a small little mistake when updating from 3.4.0 to 3.6.0 and using the mapbox-gl types. TransformRequestFunction
seems to be deprecated and replaced by RequestTransformFunction
. But RequestTransformFunction
is not exposed inside the package causing type issues. Any chance RequestTransformFunction
can get exposed on 3.6.1?
Apart from that seems like the Map type references to itself or something because as soon as I try to pass it as an argument through one of my functions; Type instantiation is excessively deep and possibly infinite.ts(2589)
. It's not a major issue and understandable from the Map perspective, but maybe it can be addressed.
Hello,
It's look like a mistake is made for the function addLayer
My code:
map?.addLayer(
{
id,
layout: {
'line-join': 'round',
'line-cap': 'round',
},
paint: {
'line-color': ['get', 'color'],
'line-width': 6,
},
source: {
type: 'geojson',
data: {
type: 'FeatureCollection',
features: features(),
},
} as unknown as mapboxgl.GeoJSONSource,
type: 'line',
},
'lines',
)
}
I got the next error:
I check the documentation and we can use an object and it's required when the type isn't custom
or background
like in my case
Apart from that seems like the Map type references to itself or something because as soon as I try to pass it as an argument through one of my functions; Type instantiation is excessively deep and possibly infinite.ts(2589). It's not a major issue and understandable from the Map perspective, but maybe it can be addressed.
This is pretty annoying, any chance to fix it?
I also don't quite understand why new mapboxgl.Map()
returns Map$1
instead of mapboxgl.Map
:
Migrating from
@types/mapbox-gl
to first-class TypeScript typingsThe GL JS v3.5.0 release marks a significant transition for GL JS, moving from Flow to TypeScript. While we have maintained backward compatibility where possible, the community typings
@types/mapbox-gl
are not fully compatible with the new first-class typings. Users relying on the community typings may experience breaking changes. This guide will help you migrate to the new first-class typings and resolve common issues.Please feel free to comment on this issue if you encounter difficulties during migration. Share your experiences and suggestions to support one another.
Updating GL JS
Install the latest version of GL JS and remove the
@types/mapbox-gl
dependency.Run the TypeScript compiler (
tsc
) to check for the errors.Common issues
The migration should be straightforward since there's no need to change how you interact with the API; only the types have changed. However, you may encounter some common issues.
Dangling
@types/mapbox-gl
Ensure you're using the latest version of GL JS and have removed the
@types/mapbox-gl
dependency.Deprecated Features
Community typings provided features deprecated since v1 and v2, such as the
optimizeForTerrain
map option,tiledata
andtiledataloading
events, zoom and property functions, certain exports like themapboxgl.Control
. Please refer to the compatibility test suite intest/build/typings/compatibility-test.ts
, used to test first-class typings compatibility with the community typings. Tests incompatible withmapbox-gl
typings are marked with@ts-expect-error - incompatible
.Naming Conventions
Community typings' naming convention slightly differs from those provided with GL JS:
*Specification
(e.g.,StyleSpecification
,LayerSpecification
), whereas in@types/mapbox-gl
, there's no suffix (e.g.,Style
,AnyLayer
).FillLayout
andFillPaint
. Instead, use TypeScript Indexed Access TypeFillLayerSpecification['layout']
for layout properties andFillLayerSpecification['paint']
for paint properties.Impl
suffix. For example,VectorSourceImpl
is exported asVectorSource
.Any*
types follow the same pattern:AnySourceData
becomesSourceSpecification
in GL JS,AnyLayer
becomesLayerSpecification
, andAnySourceImpl
becomesSource
.Note: We've created aliases where possible (e.g.,
MapboxOptions
as an alias toMapOptions
) and marked these aliases as@deprecated
in the first-class typings (this might be visible in your editor, e.g., with strikethrough style in VSCode IntelliSense). However, due to potential collisions, we couldn't create aliases for all cases. For example, we couldn't aliasSource
toSourceSpecification
because GL JS already exportsSource
(same asAnySourceImpl
in community typings). We recommend using the new naming convention, but aliases will help you migrate smoothly. Please note that these deprecated types will be removed in future releases.