Skip to content

Conversation

zirkelc
Copy link

@zirkelc zirkelc commented Mar 19, 2025

Hi,

I added some types for processInputs and processOutputs of traceable().

The input types are inferred by the same logic as runInputsToMap():

const runInputsToMap = (rawInputs: unknown[]) => {
const firstInput = rawInputs[0];
let inputs: KVMap;
if (firstInput == null) {
inputs = {};
} else if (rawInputs.length > 1) {
inputs = { args: rawInputs };
} else if (isKVMap(firstInput)) {
inputs = firstInput;
} else {
inputs = { input: firstInput };
}
return inputs;
};

The output types follow the logic of handleRunOutputs:

const handleRunOutputs = (
rawOutputs: unknown,
processOutputs: (outputs: Readonly<KVMap>) => KVMap
): KVMap => {
let outputs: KVMap;
if (isKVMap(rawOutputs)) {
outputs = rawOutputs;
} else {
outputs = { outputs: rawOutputs };
}
try {
return processOutputs(outputs);
} catch (e) {
console.error(
"Error occurred during processOutputs. Sending raw outputs:",
e
);
return outputs;
}
};

I left some test code at the end of the function, so you can easily verify the type inference:

const singlePrimitiveArg = traceable((a: string) => a, {
  processInputs: (inputs) => ({ a: inputs.input }),
  //                ^? Readonly<{ input: string; }>
  processOutputs: (outputs) => ({ a: outputs.outputs }),
  //                ^? Readonly<{ outputs: string; }>
});
const singleRecordArg = traceable((a: { a: number }) => a, {
  processInputs: (inputs) => ({ a: inputs.a }),
  //                ^? Readonly<{ a: number }>
  processOutputs: (outputs) => ({ a: outputs.a }),
  //                ^? Readonly<{ a: number }>
});
const multiplePrimitiveArgs = traceable((a: string, b: number) => ({ a, b }), {
  processInputs: (inputs) => ({ a: inputs.args[0], b: inputs.args[1] }),
  //                ^? Readonly<{ args: [a: string, b: number]; }>
  processOutputs: (outputs) => ({ a: outputs.a, b: outputs.b }),
  //                ^? Readonly<{ a: string; b: number; }>
});
const multipleRecordArgs = traceable(
  (a: { a: number }, b: { b: string }) => ({ a: a.a, b: b.b }),
  {
    processInputs: (inputs) => ({ a: inputs.args[0].a, b: inputs.args[1].b }),
    //                ^? Readonly<{ args: [{ a: number }, { b: string }]; }>
    processOutputs: (outputs) => ({ a: outputs.a, b: outputs.b }),
    //                ^? Readonly<{ a: number; b: string; }>
  }
);
const noArgs = traceable(() => undefined, {
  processInputs: (inputs) => inputs,
  //                ^? Readonly<Record<string, never>>
  processOutputs: (outputs) => outputs,
  //                ^? Readonly<{ outputs: undefined; }>
});

If it's all good, I can remove this section before merging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant