Juliusz Gonera
Juliusz Gonera

Reputation: 4968

Dynamic return type based on an array argument

I'm trying to write a function that will return an object whose keys are going to be the same as the values of the input array:

type PathParam = 'userId' | 'groupId' | 'commentId';

function usePathParams(params: PathParam[]) {
  return params.reduce(
    (acc, param) => ({ ...acc, [param]: 'whatever' }),
    {} as Record<typeof params[number], string>,
  );
}

// OK
const { userId } = usePathParams(['userId', 'commentId']);
// Should be an error but is not
const { userId, groupId } = usePathParams(['userId', 'commentId']);
// Passing a tuple doesn't seem to work either
const { userId, groupId } = usePathParams(['userId', 'commentId'] as const);

Is there any way to achieve this?

Upvotes: 0

Views: 296

Answers (1)

Linda Paiste
Linda Paiste

Reputation: 42298

In order to get an error on your second case, we need to use a generic to know which specific keys were passed.

function usePathParams<Params extends PathParam>(params: Params[]) {
  return params.reduce(
    (acc, param) => ({ ...acc, [param]: 'whatever' }),
    {} as Record<Params, string>,
  );
}

We now get the desired error Property groupId does not exist on type Record<"userId" | "commentId", string>

Your third example still has an error because as const makes the tuple readonly. If you wanted to support this, you would change the function arguments to (params: readonly Params[]). That actually allows both readonly and mutable arrays. It says that we only require read functionality.

Upvotes: 1

Related Questions