0

Question was already asked here but both the solutions provided don't address nor solve the issue

I was following some TypeScripts examples about generics, in the specific this one.

The example is pretty straightforward:

function pickObjectKeys<T, K extends keyof T>(obj: T, keys: K[]) {
  let result = {} as Pick<T, K>
  for (const key of keys) {
    if (key in obj) {
      result[key] = obj[key]
    }
  }
  return result
}

const language = {
  name: "TypeScript",
  age: 8,
  extensions: ['ts', 'tsx']
}

const ageAndExtensions = pickObjectKeys(language, ['age', 'extensions'])

This works. However, if passing the array as a variable, like so:

const keys = ['age', 'extensions']

...

pickObjectKeys(language, keys)

the TypeScript compiler gives error 2345:

Argument of type 'string[]' is not assignable to parameter of type '("age" | "extensions" | "name")[]'.
Type 'string' is not assignable to type '"age" | "extensions" | "name"'.

What's the catch? How to address this issue?

3
  • 2
    keys is inferred as string[], not ["age", "extensions"] or ("age" | "extensions")[]. Commented Oct 22, 2022 at 13:31
  • @caTS Ah, makes sense. So how would you address it? Assume that you may want to be able to pass a variable to the function Commented Oct 22, 2022 at 13:35
  • 1
    const keys : ("age" | "extensions")[] = ["age", "extensions"] or const keys = ["age" | "extensions"] as ("age" | "extensions")[]. Because if you just do const keys = ["age", "extensions"] it's totally legal to do keys.push("foobar") but that would cause an error in pickObjectKeys Commented Oct 22, 2022 at 13:36

1 Answer 1

1

First, consider making keys readonly:

function pickObjectKeys<T, K extends keyof T>(obj: T, keys: readonly K[]) {

this will allow you to pass readonly arrays now (previously it would've errored).

The easiest way to get around this is to use a const assertion:

const keys = ['age', 'extensions'] as const; // readonly ["age", "extensions"]

pickObjectKeys(language, keys); // OK

but you could also cast to ["age", "extensions"] or ("age" | "extensions")[]. However, that does mean you would repeat yourself, so I suggest staying with as const.

Playground

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.