Typed arrays and batch calls
Audience: package users working with many cells at once. Cell sets cross the boundary as one
BigUint64Array, coordinate sets as oneFloat64Array, and three batch calls run a whole array in one native call. This page gives their exact contract.
Cell sets are typed arrays
Section titled “Cell sets are typed arrays”Cell collections use BigUint64Array:
import { gridDisk, latLngToCell } from 'react-native-nitro-h3'
const cell = latLngToCell(37.7749, -122.4194, 9)const cells = gridDisk(cell, 10)
console.log(cells instanceof BigUint64Array) // trueA result crosses as one ArrayBuffer and is viewed in place: no per-element copy, no string
conversion.
The batch calls
Section titled “The batch calls”Three additional APIs process complete typed arrays in a single native call:
import { latLngsToCells, cellsToLatLngs, cellsToBoundaries,} from 'react-native-nitro-h3'
const coords = new Float64Array([ 37.7749, -122.4194, 37.8044, -122.2712,])
const cells = latLngsToCells(coords, 9)// BigUint64Array
const centres = cellsToLatLngs(cells)// Float64Array: [lat0, lng0, lat1, lng1, ...]Coordinates use interleaved [latitude, longitude] pairs.
These APIs are additive and are not part of the h3-js compatibility surface, which Divergences from h3-js 4.5.0 records and a test asserts. They are intended for workloads where repeatedly crossing the JS/native boundary would otherwise dominate execution time.
The saving is the crossing, not a faster inner loop. Host measurements put the native work of
latLngsToCells and cellsToLatLngs within about 2 % of the native work of the loop each replaces,
so what disappears is the per-element boundary crossing.
latLngsToCells
Section titled “latLngsToCells”function latLngsToCells(coords: Float64Array, res: number): BigUint64ArrayIndexes a whole coordinate set in one native call. coords is interleaved
[lat0, lng0, lat1, lng1, ...] in degrees, latitude first, the reverse of the GeoJSON order.
Returns one cell per pair, in input order.
- An odd
coords.lengththrows anH3ErrorreadingA coordinate set must hold an even number of doubles. - A rejected pair throws an
H3Errorwhose message carries its index, as incoords[3]: .... - A
resoutside0to15is rejected on the first pair, so the message readscoords[0]: Resolution argument was outside of acceptable range (code: 4). - An empty
coordsreturns an emptyBigUint64Array, andresis never judged. - The cell ceiling applies, counted in cells: one cell per pair.
cellsToLatLngs
Section titled “cellsToLatLngs”function cellsToLatLngs(cells: BigUint64Array): Float64ArrayReads the centres of a whole cell set in one native call. Returns interleaved
[lat0, lng0, lat1, lng1, ...] in degrees, latitude first again, two entries per cell, which is the
flat coordinate buffer circle layers and heatmaps consume.
- An invalid cell throws an
H3Errorwhose message carries its index, such ascells[1]: Cell argument was not valid (code: 5). - An empty
cellsreturns an emptyFloat64Array, and no element is validated. - The cell ceiling applies, counted in cells, and is checked before the first centre is read.
cellsToBoundaries
Section titled “cellsToBoundaries”function cellsToBoundaries(cells: BigUint64Array): CellBoundaries
interface CellBoundaries { stride: number vertices: Float64Array vertexCounts: Uint8Array}Reads the boundary of every cell in one native call, into a fixed-stride buffer a renderer can walk by index:
const { stride, vertices, vertexCounts } = cellsToBoundaries(cells)for (let i = 0; i < cells.length; i++) { const base = i * stride for (let j = 0; j < vertexCounts[i]; j++) { path.lineTo(project(vertices[base + 2 * j], vertices[base + 2 * j + 1])) }}strideis always20, ten[lat, lng]pairs, which is H3’sMAX_CELL_BNDRY_VERTSdoubled. Cellistarts ati * stride, so any cell is reached without a scan.vertexCounts[i]is how many of those pairs are real:5for a pentagon at an even resolution and10at an odd one,6for a hexagon,7or8where a hexagon crosses an icosahedron edge.- Slots past the count hold
NaN, never0, so a read past the count is visible instead of landing off the coast of Africa. - Vertices are in the same order and the same degrees
cellToBoundaryanswers, latitude first. - An invalid cell throws an
H3Errorwhose message carries its index, such ascells[1]: Cell argument was not valid (code: 5). - An empty
cellsreturns empty arrays, withstridestill20. - The cell ceiling applies, counted in cells, and is checked before anything is allocated. One cell weighs 161 bytes here, 160 of vertices and 1 of count, rather than the 8 bytes of a cell set.
What a batch call saves
Section titled “What a batch call saves”The saving is the bridge crossings that no longer happen. Same conditions as the headline benchmark: iPhone XS, iOS 18.7.9, React Native 0.87.0, Hermes, 20-run median, 2026-09-01. Full data in Benchmark report.
Whether a batch call pays for a given input size is covered in
Performance guide, and the measured rows are W11 and
W12 in Benchmark report.