[英]Convert a string to object key lookup in typescript
I have a use case where I need to use a string to match object values我有一个用例,我需要使用字符串来匹配对象值
For example例如
'one': {
'two': {
'three': 'val'
}
}
}
split
and reduce
seems to be the way to go about this, but I have not gotten it to work using the code below split
和reduce
似乎是解决这个问题的方法,但我还没有使用下面的代码让它工作
const string = 'one.two.three';
const test = string
.split('.')
.reduce((obj, key) => {
return obj[key]
});
console.log(test);
//expected one['two']['three']
[ Edit to add more context ] I have an HTML Template (angular 7) that calls the sort function [编辑以添加更多上下文] 我有一个调用排序函数的 HTML 模板(角度 7)
(click)="sortColumn('spn.subscriptionId')"
I have the following object to keep track of sort order for each column我有以下对象来跟踪每列的排序顺序
public sortableColumns = [
{ colName: 'name', colSortDir: 'none'},
{ colName: 'spn.subId', colSortDir: 'none'},
{ colName: 'regionName', colSortDir: 'none'},
{ colName: 'customerName', colSortDir: 'none'}
];
and the sortColumn
function.和
sortColumn
函数。 this.subscriptions
comes from a rest api. this.subscriptions
来自一个rest api。 the sort function works if there is a rest api object only has one level - 'name' but does not work for the nested object - spn.subscriptionId
如果rest api 对象只有一个级别,则排序函数有效 - 'name' 但不适用于嵌套对象 -
spn.subscriptionId
public sortColumn(column : string) {
// resets other columns
this.sortableColumns.forEach((el) => {
if (el.colName !== column) {
el.colSortDir = 'none';
}
});
// matches the column name passed with sortableColumns to set order in UI
const col = this.sortableColumns.filter((el) => {
return el.colName === column;
});
// sorting of the array object. this.subscriptions comes fr
if (col[0].colSortDir === 'asc') {
col[0].colSortDir = 'dsc';
this.subscriptions.sort((val1, val2) => {
if (val1[column] < val2[column]) {
return -1;
} else if (val1[column] > val2[column]) {
return 1;
} else {
return 0;
}
});
} else if (col[0].colSortDir === 'none' || col[0].colSortDir === 'dsc') {
col[0].colSortDir = 'asc';
this.subscriptions.sort((val1, val2) => {
if (val1[column] > val2[column]) {
return -1;
} else if (val1[column] < val2[column]) {
return 1;
} else {
return 0;
}
});
}
}
There is no magic "lookup key" that you can plug in to the bracket notation obj[key]
and have it traverse multiple nested objects.没有神奇的“查找键”可以插入括号表示法
obj[key]
并让它遍历多个嵌套对象。
Given your expected use case, it makes the most sense to have a lookup function that takes a compound key and uses your .split().reduce()
method to fetch the desired value in the nested objects.考虑到您预期的用例,使用复合键并使用您的
.split().reduce()
方法在嵌套对象中获取所需值的查找函数最有意义。
So, something like this:所以,像这样:
function lookup(obj : object, key : string) : any {
return key.split('.').reduce((o, k) => o && o[k], obj);
}
Used like this:像这样使用:
this.subscriptions.sort((val1, val2) => {
return lookup(val1,column) - lookup(val2,column);
});
It looks like your problem was not passing the actual object in as the initialValue
parameter .看起来您的问题不是将实际对象作为
initialValue
参数传入。
We can write a nestedProp()
function which takes an object and a path string and walks through it:我们可以编写一个
nestedProp()
函数,它接受一个对象和一个路径字符串并遍历它:
function nestedProp(obj: object, path: string): unknown {
return path.split(".").reduce((o, k) => o ? (o as any)[k] : undefined, obj);
}
All I've really done is add obj
as initialValue
.我真正做的就是将
obj
添加为initialValue
。 I also guard against o[k]
being null
or undefined
so that the code doesn't throw runtime errors if you pass a bad string.我还防止
o[k]
为null
或undefined
以便在传递错误字符串时代码不会抛出运行时错误。
Also note that the type definitions I've given are really very loose;另请注意,我给出的类型定义非常松散;
obj
is any object
, path
is any string
, and it returns unknown
. obj
是任何object
, path
是任何string
,它返回unknown
。 That's because TypeScript can't do string manipulation at the type level, so it has no idea that "one.two.three".split(".")
will result in ["one", "two", "three"]
and therefore no idea that nestedProp()
should produce a string
instead of an undefined
which is what happens when you pass in, say, "oops.not.a.property"
.那是因为 TypeScript 不能在类型层面做字符串操作,所以不知道
"one.two.three".split(".")
会导致["one", "two", "three"]
因此,不知道nestedProp()
应该生成一个string
而不是一个undefined
的string
,这是您传入时会发生的情况,例如, "oops.not.a.property"
。 It's possible to tighten the definitions up a little, but it doesn't seem worth it.可以稍微收紧定义,但这似乎不值得。 To be safe you should test that the output is what you want.
为了安全起见,您应该测试输出是否是您想要的。
So, let's test it.那么,让我们来测试一下。 Say your object is this:
说你的对象是这样的:
const myObj = {
'one': {
'two': {
'three': 'val'
}
}
}
Then you can call nestedProp()
like this:然后你可以像这样调用
nestedProp()
:
const res1 = nestedProp(myObj, "one.two.three");
console.log(res1); // "val"
console.log((typeof res1 === "string" ? res1 : "oops").toUpperCase()); // VAL
const res2 = nestedProp(myObj, "three.two.one");
console.log(res2); // undefined
console.log((typeof res2 === "string" ? res2 : "oops").toUpperCase()); // OOPS
Looks good to me.在我看来很好。 Note that I'm testing if the output is a
string
before assuming it is one, and using "oops"
in the case that it isn't.请注意,在假设它是一个之前,我正在测试输出是否是一个
string
,如果不是,则使用"oops"
。 Okay, hope that helps;好的,希望有帮助; good luck!
祝你好运!
let string = "one.two.three.four.five.six";
let stringArr = string.split('.');
let obj = {
[stringArr[stringArr.length - 1]]: "value",
}
for (let i = stringArr.length - 2; i >= 0; i--) {
this[stringArr[i]] = obj
obj = Object.assign({}, this)
delete this[stringArr[i]]
}
console.log(JSON.stringify(obj))
This works for any number of nesting.这适用于任意数量的嵌套。
{"one":{"two":{"three":{"four":{"five":{"six":"value"}}}}}}
I hope this is what you want我希望这是你想要的
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.