I have a complex interface. A simpler version of it would be something like this
Interface Person {
'name': string, 'address': string, 'age': number, 'height': number
}
const person:Person = {'name': 'Yair', 'address': 'here', 'age': 12, 'height': 186}
Now say I wanted to create a function to dynamically update the name or address. This works well:
let updateNameOrAddress = (key: "name"|"address", value: string): void => {
person[key] = value
}
However, defining keys this way will get hard when I'll add more and more string fields. So I try something like this:
let updateNameOrAddress = (key: keyof Person, value: string): void => {
person[key] = value
}
Well, this creates this error: Type 'string' is not assignable to type 'never' I have reasons to believe that this is because name can now also be "age" or "height". I'd stick to adding types as possibilities for "name" - but my real object has lots of values. Is there a way to get keyof, to retrive only the string / numberic keys?
Thanks in advance
CodePudding user response:
Using generics you can check the changed key and map it onto Person
to retrieve the property's value type generically.
Notice that T
is accessing Person[T]
, this means that the type of the value
parameter can be determined based on the given key
argument.
interface Person {
'name': string, 'address': string, 'age': number, 'height': number
}
const person: Person = { 'name': 'Yair', 'address': 'here', 'age': 12, 'height': 186 }
const updateNameOrAddress = <T extends keyof Person>(key: T, value: Person[T]): void => {
person[key] = value;
}
updateNameOrAddress("name", "John"); // Ok
updateNameOrAddress("age", "47"); // Error!
updateNameOrAddress("age", 47); // Ok
CodePudding user response:
Is there a way to get keyof, to retrive only the string / numberic keys?
interface Person {
'name': string;
'address': string;
'age': number;
'height': number;
}
type KeysOfType<T, U> = {
[K in keyof T]: T[K] extends U ? K : never
}[keyof T];
const person: Person = { 'name': 'Yair', 'address': 'here', 'age': 12, 'height': 186 }
let updateNameOrAddress = (key: KeysOfType<Person, string>, value: string): void => {
person[key] = value
}