Home > Software engineering >  Typescript - Curried Function Argument For Object Property
Typescript - Curried Function Argument For Object Property

Time:03-04

I'm trying to preset a property of an object which is passed as an argument to a function. This way i don't have to set this specific property as it is already provided when i call this function later.

The use case is to set the version for api calls.

withApiVersion

const API_VERSION = "1";

const addApiVersion = <T>(obj: T) => ({ ...obj, version: API_VERSION });

export const withApiVersion = <Fn extends (arg: any) => any>(fn: Fn) => <Arg>(
  arg: Arg
): ReturnType<Fn> => fn(addApiVersion(arg));

Example api method

export const getCertificates = ({
  version,
  searchString,
  skip,
  take = 50
}: {
  version: string;
  searchString?: string;
  skip?: number;
  take?: number;
}) => Promise.resolve([{ id: 1 }]);
const result = withApiVersion(getCertificates);

Everything works fine except that i can't get the correct type after the "partial application" of the function's argument -> ideally withApiVersion will return a function which expects an argument where the version property is missing.

Edit optimistic-mcclintock-ky387e

Thx in advance for any help or tipp!

CodePudding user response:

You can use Omit to take out some props from Arg. Also Arg should be inferred on the first function as it comes from the function. You don't need to capture the actual type of the function, you are interested in the result and the argument, so use those as your type parameters:

export const withApiVersion = <Arg extends { version: string }, Result>(fn: (arg: Arg | (Omit<Arg, "version"> & { version: string; })) => Result) => (
  arg: Omit<Arg, 'version'>
): Result => fn(addApiVersion(arg));

Playground Link

Arg and (Omit<Arg, "version"> & { version: string; }) should resolve to the same thing, but typescript can't figure that out because of the conditional type in Omit. To not need any assertions in the body of our function, we use the two equivalent types in a union. This will allow he implementation to use the (Omit<Arg, "version"> & { version: string; }) constituent as the argument to the function, while at call site the two should resolve to the same type and not cause any issues.

  • Related