Repository: plotly/dash
File: dash/dash-renderer/src/actions/callbacks.ts (TypeScript)

Code before:

    try {
        const {namespace, function_name} = clientside_function;
        let args = inputs.map(getVals);
        if (state) {
            args = concat(args, state.map(getVals));
        }

        // setup callback context
        dc.callback_context = {};
        dc.callback_context.triggered = payload.changedPropIds.map(prop_id => ({
            prop_id: prop_id,
            value: inputDict[prop_id]
        }));
        dc.callback_context.triggered_id = getTriggeredId(
            payload.changedPropIds
        );
        dc.callback_context.inputs_list = inputs;
        dc.callback_context.inputs = inputDict;
        dc.callback_context.states_list = state;
        dc.callback_context.states = stateDict;
        dc.callback_context.outputs_list =
            Object.prototype.toString.call(outputs) === '[object Object]'
                ? [outputs]
                : outputs;
        dc.callback_context.outputs = output;

        let returnValue = dc[namespace][function_name](...args);

        delete dc.callback_context;

        if (typeof returnValue?.then === 'function') {
            returnValue = await returnValue;
        }

        if (outputs) {
            zipIfArray(outputs, returnValue).forEach(([outi, reti]) => {
                zipIfArray(outi, reti).forEach(([outij, retij]) => {
                    const {id, property} = outij;
                    const idStr = stringifyId(id);
                    const dataForId = (result[idStr] = result[idStr] || {});
                    if (retij !== dc.no_update) {
                        dataForId[cleanOutputProp(property)] = retij;
                    }
                });
            });
        }
    } catch (e) {
        if (e === dc.PreventUpdate) {
            status = STATUS.PREVENT_UPDATE;
        } else {

Review comment (suggestion):
It would be best to make the client side `callback_context` be the same as what's available on the server side.  To achieve this, I think all that's necessary is to add the following here:

```
dc.callback_context.outputs_list = outputs;
```



Code after:
    const stateDict = inputsToDict(state);
    const result: any = {};
    let status: any = STATUS.OK;

    try {
        const {namespace, function_name} = clientside_function;
        let args = inputs.map(getVals);
        if (state) {
            args = concat(args, state.map(getVals));
        }

        // setup callback context
        dc.callback_context = {};
        dc.callback_context.triggered = payload.changedPropIds.map(prop_id => ({
            prop_id: prop_id,
            value: inputDict[prop_id]
        }));
        dc.callback_context.triggered_id = getTriggeredId(
            payload.changedPropIds
        );
        dc.callback_context.inputs_list = inputs;
        dc.callback_context.inputs = inputDict;
        dc.callback_context.states_list = state;
        dc.callback_context.states = stateDict;
        dc.callback_context.outputs_list = outputs;

        let returnValue = dc[namespace][function_name](...args);

        delete dc.callback_context;

        if (typeof returnValue?.then === 'function') {
            returnValue = await returnValue;
        }

        if (outputs) {
            zipIfArray(outputs, returnValue).forEach(([outi, reti]) => {
                zipIfArray(outi, reti).forEach(([outij, retij]) => {
                    const {id, property} = outij;
                    const idStr = stringifyId(id);
                    const dataForId = (result[idStr] = result[idStr] || {});
                    if (retij !== dc.no_update) {
                        dataForId[cleanOutputProp(property)] = retij;
                    }
                });
            });
        }
    } catch (e) {
        if (e === dc.PreventUpdate) {
            status = STATUS.PREVENT_UPDATE;
        } else {
            status = STATUS.CLIENTSIDE_ERROR;