The point of using real address with XIP is to run in place, when you have e.g. string variable pointing to string data (
var s="whatever") or js function variable pointing to the start of the code to interpret, it can use address pointing directly to the address in flash managed by XIP so CPU can directly read the data from flash without any copy in RAM.
That's how the Storage module on top of Flash module works (on nrf5x and STM32 at least). Not sure how this works in ESP port in this regard, whether js code stored in flash in Storage file can be directly used for variable data and is directly accessible by CPU or it must be loaded to RAM first.
for NRF the flash addresses from Flash.getFree() is either real memory address for internal flash memory which is directly accessible by CPU or with Bangle watches the SPI flash is mapped to 0x60000000 and direct access is faked as there is no XIP but still there is a hack to use data 'in place' via specific JSV_FLASH_STRING type https://github.com/espruino/Espruino/blob/master/src/jsvar.h#L75 so data does not take RAM but it loaded from flash on demand when iterating over it.
Anyway what I wanted to say is that having flash storage starting from flash location zero and then having real memory mapping of flash data where CPU really sees it in different place can make things more confusing.
So as Pico/RP2040 can see whole 2-16MB SPI flash directly mapped starting at 0x10000000 I'd use that.
Testing for negative value can be used too but it may cause bugs when using unsigned type somewhere.