How do I properly traverse an object in Ts
The article was first published on a personal blog
This is a short article…
JavaScript
Before going over an object with Ts, let’s talk about how to implement this in Js. In, object. keys, a simple example:
// for... in
const obj = {
name: 'itsuki'.address: 'hangzhou'};for (const key in obj) {
console.log(key, obj[key].toUpperCase());
}
// Object.keys
Object.keys(obj).forEach(key= > {
console.log(key, obj[key].toUpperCase());
});
/ / output
// name ITSUKI
// address HANGZHOU
Copy the code
TypeScript
for… in
But in TypeScript, if you do this directly, you’ll get an error.
type Person = {
name: string;
address: string;
};
const obj: Person = {
name: 'itsuki'.address: 'hangzhou'};function print(obj: Person) {
for (const key in obj) {
/ / ❌
// key:string cannot be assigned to {name:string; Age: number} type
console.log(key, obj[key].toUpperCase());
}
}
print(obj)
Copy the code
We know for… Keys can’t be assigned to a Person’s name or address because all keys in an Object are strings.
But we can solve this problem by keyof.
function print(obj:Person){
let key: keyof Person;
for (key in obj) {
/ / ✅
console.log(key, obj[key].toUpperCase()); }}Copy the code
Object.keys
When using object. keys, we can use the AS operator.
function print(obj: Person) {
Object.keys(obj).forEach((k) = > {
/ / ✅
console.log(k, obj[k as keyof Person].toUpperCase());
});
}
Copy the code
We can pull this out as a function:
function getKeys<T> (obj: T) {
return Object.keys(obj) as Array<keyof T>;
}
getKeys(obj); // (keyof Person)[]
Copy the code
Object.entries
We can also use object.entries () to traverse objects.
Object.entries(obj).forEach(([k, v]) = > {
console.log(k, v);
});
Copy the code
thinking
The following is my own thinking, if there is any mistake, please correct
I think the Object. The keys () returns a string [], because it is set at run time, that we do know the TypeScript is static type checking, even if we use keyof Person returned to the name | address, But we can’t be sure it will be those two fields at run time.
Such as:
const obj2 = {
name: 'itsuki'.address: 'hangzhou'.age: 20}; print(obj2)// compile time: ✅, because it has name, address attributes
// Runtime: ❌, since the age field is number, there is no toUpperCase method
Copy the code
Then I found this sentence in Github issue:
Types in TS are open-ended. Therefore, keysof may be less than all the attributes acquired at run time.
Keys () returns a string[] instead of a (keyof Person)[].