diff --git a/javascript/src/rpc.spec.ts b/javascript/src/rpc.spec.ts index b5fd6c9..e866a47 100644 --- a/javascript/src/rpc.spec.ts +++ b/javascript/src/rpc.spec.ts @@ -758,18 +758,52 @@ describe('RetoolRPC', () => { arguments: {}, implementation: async () => { return 1 - } + }, }) type ExpectedImplementation = (args: TransformedArguments, context: RetoolContext) => Promise expectTypeOf(fn).toEqualTypeOf() - - const result = await fn({}, context); + const result = await fn({}, context) expect(result).toEqual(1) expectTypeOf(result).toEqualTypeOf(1) }) + test('infers non-required properties as optional', async () => { + const fn = rpcAgent.register({ + name: 'test', + arguments: { + explicitRequired: { + type: 'number', + required: true, + }, + explicitOptional: { + type: 'number', + required: false, + }, + implicitOptional: { + type: 'number', + }, + }, + implementation: async (args) => { + expectTypeOf(args.explicitRequired).toEqualTypeOf() + + expectTypeOf(args.explicitOptional).toEqualTypeOf() + expectTypeOf(args.implicitOptional).toEqualTypeOf() + + return args + }, + }) + + const result = await fn( + { + explicitRequired: 1, + }, + context, + ) + + expectTypeOf(result.explicitOptional).toEqualTypeOf() + }) }) describe('RetoolRPCVersion', () => { diff --git a/javascript/src/rpc.ts b/javascript/src/rpc.ts index 94f1757..d715e57 100644 --- a/javascript/src/rpc.ts +++ b/javascript/src/rpc.ts @@ -89,13 +89,15 @@ export class RetoolRPC { /** * Registers a Retool function with the specified function definition. */ - register(spec: RegisterFunctionSpec): RegisterFunctionSpec['implementation'] { + register( + spec: RegisterFunctionSpec, + ): RegisterFunctionSpec['implementation'] { this._functions[spec.name] = { arguments: spec.arguments, permissions: spec.permissions, - implementation: spec.implementation, + implementation: spec.implementation as RegisterFunctionSpec['implementation'], } - return spec.implementation; + return spec.implementation } /** diff --git a/javascript/src/types.ts b/javascript/src/types.ts index 93e3dfa..6d9662d 100644 --- a/javascript/src/types.ts +++ b/javascript/src/types.ts @@ -36,11 +36,17 @@ export type ArgumentType = 'string' | 'boolean' | 'number' | 'dict' | 'json' export type Argument = { /** The type of the argument. */ type: ArgumentType - /** Specifies whether the argument is expected to be an array. */ + /** + * Specifies whether the argument is expected to be an array. + * @default false + */ array?: boolean /** The description of the argument. */ description?: string - /** Specifies whether the argument is required. */ + /** + * Specifies whether the argument is required. + * @default false + */ required?: boolean } @@ -68,10 +74,18 @@ export type TransformedArgument = TArg['array'] extends t ? Array> : ArgumentTypeMap +type PartialBy = Omit & Partial> +type GetOptionalArgs = { + [TArg in keyof TArgs]: TArgs[TArg]['required'] extends true ? never : TArg +}[keyof TArgs] + /** Represents a map of argument names to argument types. */ -export type TransformedArguments = { - [TArg in keyof TArgs]: TransformedArgument -} +export type TransformedArguments = PartialBy< + { + [TArg in keyof TArgs]: TransformedArgument + }, + GetOptionalArgs +> /** Represents the specification for registering a Retool function. */ export type RegisterFunctionSpec = { diff --git a/javascript/tsconfig.json b/javascript/tsconfig.json index e096887..6af1a6e 100644 --- a/javascript/tsconfig.json +++ b/javascript/tsconfig.json @@ -11,7 +11,7 @@ /* Additional Checks */ "skipLibCheck": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true, + "allowSyntheticDefaultImports": true }, "ts-node": { // these options are overrides used only by ts-node @@ -19,5 +19,5 @@ "compilerOptions": { "module": "commonjs" } - }, + } }