Deftomat
Deftomat

Reputation: 629

Typescript: list of keys into the object with the same keys and values based on key content

We need to type the function, which requires a list of keys (strings) and produces object with the same keys where values are string | undefined when key starts with ? or otherwise just string.

export function useParams<T extends string>(
  expected: T[]
): { [key in T as NonOptional<T>]: string } {
  // ... our custom implementation
  return null as any;
}

type NonOptional<T extends string> = T extends `?${infer Inner}` ? Inner : T;

// Should produce type { a: string; b: string | undefined }
const result = useParams(['a', '?b']);

However, I'm not sure how to type the output.

Upvotes: 0

Views: 896

Answers (1)

aleksxor
aleksxor

Reputation: 8380

You may write it iterating over tuple's keys:

export function useParams<T extends readonly string[]>(
  expected: T
): { [K in T[number] as NonOptional<K>]: string | OrUndefined<K> } {
  return null as any;
}

type NonOptional<T extends string> = T extends `?${infer Inner}` ? Inner : T;
type OrUndefined<T extends string> = T extends `?${string}` ? undefined : never

const result = useParams(['a', '?b'] as const);

playground link


Added section to address the problem described in comments:

I'm pretty sure developers will forgot to add as const and then it will stop working correctly.

To allow passing non-readonly tuples you may use variadic tuple types:

export function useParams<T extends string[]>(
  expected: [...T]
): { [K in T[number] as NonOptional<K>]: string | OrUndefined<K> } {
  return null as any;
}

type NonOptional<T extends string> = T extends `?${infer Inner}` ? Inner : T;
type OrUndefined<T extends string> = T extends `?${string}` ? undefined : never

const result = useParams(['a', '?b']);

playground link

Upvotes: 1

Related Questions