Home > Back-end >  Type of array of functions that return only keys from object
Type of array of functions that return only keys from object

Time:08-21

I have the following object:

interface User {
  id: string;
  name: string;
}

Then I have the following object that represents what can be updated in the backend for a user:

type UpdateUserBody = Pick<User, 'name'>;

Now I would like to have an array of functions that ONLY return a single property of UpdateUserBody.

What I have tried so far:

[
  () => user.name
] as Array<() => keyof UpdateUserBody>

The problem is that if I add () => user.id to the array, it doesn't throw an error:

[
  () => user.name,
  () => user.id,
] as Array<() => keyof UpdateUserBody>

Why I have to do it in this way

I'm using Vuejs's watchers to watch these properties to save a draft of a user whenever the current logged user is creating a new user. In my watchers I'm doing:

const unwatchUserUpdateRequest = watch(
  [
    () => user.name,
  ] as Array<() => keyof UpdateUserBody>,
  updateUserApiRequest,
)

I have tried a few other small things that came to mind but nothing helped me solve the issue.

How can I allow that the array only has functions that return the properties of UpdateUserBody?

Playground here

CodePudding user response:

If you want that user.id is not accessible, you will need to modify the user type. An easy way to do this is to create the functions in a different scope and pass the user as a parameter:

interface User {
  id: string;
  name: string;
}

type UpdateUserBody = Pick<User, 'name'>;

function getUserUpdateWatchers(user: UpdateUserBody): (() => string)[] {
  return [
    () => user.name,
    () => user.id, // Property 'id' does not exist on type 'UpdateUserBody'.
  ]
}

const unwatchUserUpdateRequest = watch(
  getUserUpdateWatchers(someUser),
  updateUserApiRequest,
)

If you only want to extract keys without further functionality, you could also use a list of keys with a generic function that maps the keys to () => user[key] functions:

const unwatchUserUpdateRequest = watch(
  // Type '"id"' is not assignable to type '"name"'.
  toPropertyExtractors<UpdateUserBody>(['name', 'id'], user),
  updateUserApiRequest,
)

function toPropertyExtractors<T>(keys: (keyof T)[], object: T): (() => T[keyof T])[] {
  return keys.map(key => () => object[key])
}
  • Related