This might not be a direct answer but is definitely related and helpful to some...
I created this function a while back inspired by Laravels data_get() php function:
/**
 * Get an item from an array or object using "dot" notation.
 *
 * @param {object} source
 * @param {array|string} name
 * @param {null|*} defaultValue
 *
 * @returns {null|*}
 */
window.objectGet = function( source, name, defaultValue = null ) {
    const parts = Array.isArray( name ) ? name : name.split( '.' );
    // Duplicate array prevents modifying original by reference
    let partsTracking = Array.isArray( name ) ? name : name.split( '.' );
    for ( let i = 0; i < parts.length; i++ ) {
        const segment = parts[ i ];
        partsTracking.splice( 0, 1 );
        if ( segment === null ) {
            return source;
        }
        if ( segment === '*' ) {
            if ( !source || typeof source !== 'object' ) {
                return defaultValue;
            }
            let tmpResult = [];
            for ( var key in source ) {
                tmpResult.push( objectGet( source[ key ], partsTracking.join( '.' ), defaultValue ) );
            }
            return partsTracking.includes( '*' ) ? tmpResult.flat( Infinity ) : tmpResult;
        }
        if ( source && typeof source === 'object' && segment in source ) {
            source = source[ segment ];
        } else {
            return defaultValue;
        }
    }
    return source;
};
Example usage:
const myObject = {
    key: 'value',
    nested: {
        example: [
            'value1',
            'value2',
        ]
    }
};
console.log( objectGet( myObject, 'key' ) ); // Output: 'value'
console.log( objectGet( myObject, 'nested.example' ) ); // Output: [ 'value1', 'value2' ]
console.log( objectGet( myObject, 'nested.example.0' ) ); // Output: 'value1'
console.log( objectGet( myObject, 'nested.example.1' ) ); // Output: 'value2'
So usage in regards to OPs question might be something like:
const duration                  = objectGet( outbound, 'duration' );
const departureIataCode         = objectGet( outbound, 'segments.0.departure.iataCode' );
const departAt                  = objectGet( outbound, 'segments.0.departure.at' );
const arrivalIataCode           = objectGet( outbound, 'segments.0.arrival.iataCode' );
const arriveAt                  = objectGet( outbound, 'segments.0.arrival.at' );
const carrierCode               = objectGet( outbound, 'segments.0.carrierCode' );
const stopOverDepartureIataCode = objectGet( outbound, 'segments.1.departure.iataCode' );
const stopOverDepartAt          = objectGet( outbound, 'segments.1.departure.at' );
const finalArrivalIataCode      = objectGet( outbound, 'segments.1.arrival.iataCode' );
const finalArriveAt             = objectGet( outbound, 'segments.1.arrival.at' );
I should add that if a key isn't found, null will be returned. You can pass default values as the third parameter, for example:
const notFound = objectGet( input, 'my.data.key', 'my default value' );
You can also return an array of nest values by using * for example:
const input = {
    data: [
        {
            id: 123,
            name: 'Example 1'
        },
        {
            id: 789,
            name: 'Example 2'
        }
    ]
};
const ids = objectGet( input, 'data.*.id' ); // Ouput: [ 123, 789 ]