lyswhut
lyswhut

Reputation: 25

typescript uses generics to reorganize read-only array types

I tried to restructure the type of the read-only array, but it didn't work:

const store: Record<string, any> = {
  aaa: '123',
  bbb: null,
  ccc: []
}

const getValues = <Keys extends readonly string[]>(keys: Keys): ReadonlyArray<[Keys[number], unknown]> => {
  return keys.map((key) => ([key, key in store ? store[key] : null]))
}

const keyArr = ['aaa', 'bbb'] as const
getValues(keyArr)  // current getValues function types:  const getValues: <readonly ["aaa", "bbb"]>(keys: readonly ["aaa", "bbb"]) => readonly ["aaa" | "bbb", unknown][]

// I want:  const getValues: <readonly ["aaa", "bbb"]>(keys: readonly ["aaa", "bbb"]) => readonly [["aaa", unknown], ["bbb", unknown]]

Here is the typescript Playground code link.

Upvotes: 1

Views: 126

Answers (1)

Tobias S.
Tobias S.

Reputation: 23865

You can map over the tuple using a mapped type. Mapping over a tuple type using a mapped type also produces a tuple as a result since TypeScript 3.1.

const getValues = <Keys extends readonly string[]>(keys: Keys) => {
  return keys.map((key) => (
    [key, key in store ? store[key] : null])
  ) as { [K in keyof Keys]: [Keys[K], unknown] }
}

TypeScript is not able to correctly understand that the type of the resulting array matches the return type. So a type assertion is needed.


Playground

Upvotes: 1

Related Questions