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
?
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])
}