将字符串转换为打字稿中的对象键查找

时间:2020-02-13 17:55:18

标签: javascript angular typescript

我有一个用例,我需要使用字符串来匹配对象值

例如

'one': {
    'two': {
            'three': 'val'
        }
    }
}

splitreduce似乎是解决此问题的方法,但是我还没有使用下面的代码使它起作用

const string = 'one.two.three';
const test = string
             .split('.')
             .reduce((obj, key) => {
                 return obj[key]
             });
console.log(test); 
//expected one['two']['three'] 

[编辑以添加更多上下文] 我有一个HTML模板(角度7),它调用了sort函数

(click)="sortColumn('spn.subscriptionId')"

我有以下对象来跟踪每一列的排序顺序

public sortableColumns = [
    { colName: 'name', colSortDir: 'none'},
    { colName: 'spn.subId', colSortDir: 'none'},
    { colName: 'regionName', colSortDir: 'none'},
    { colName: 'customerName', colSortDir: 'none'}
];

sortColumn函数。 this.subscriptions来自rest api。如果存在一个剩余的api对象只有一个级别-'name',但不适用于嵌套对象-spn.subscriptionId

,则sort函数起作用
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;
            }
        });
    }
}

3 个答案:

答案 0 :(得分:1)

没有神奇的“查找键”,您可以将其插入括号表示法obj[key]中并使其遍历多个嵌套对象。

鉴于您的预期用例,使用具有复合键并使用.split().reduce()方法在嵌套对象中获取所需值的查找功能最有意义。

所以,像这样:

function lookup(obj : object, key : string) : any {
    return key.split('.').reduce((o, k) => o && o[k], obj);
}

像这样使用:

    this.subscriptions.sort((val1, val2) => {
        return lookup(val1,column) - lookup(val2,column);
    });

答案 1 :(得分:0)

您的问题似乎不是将实际对象作为the initialValue parameter传递了。

我们可以编写一个nestedProp()函数,该函数接受一个对象和一个路径字符串并遍历它:

function nestedProp(obj: object, path: string): unknown {
    return path.split(".").reduce((o, k) => o ? (o as any)[k] : undefined, obj);
}

我实际上所做的只是将obj添加为initialValue。我还防止o[k]nullundefined,以便在传递错误字符串时代码不会引发运行时错误。

还要注意,我给出的类型定义确实非常宽松; obj是任何objectpath是任何string,并返回unknown。那是因为TypeScript无法在类型级别上进行字符串操作,所以不知道"one.two.three".split(".")会产生["one", "two", "three"],因此也不知道nestedProp()应该产生{{1} }而不是string,这是您传入undefined时发生的情况。可以稍微加紧定义,但这似乎不值得。为了安全起见,应该测试输出是否是您想要的。


因此,让我们对其进行测试。说你的对象是这样的:

"oops.not.a.property"

然后您可以像这样呼叫const myObj = { 'one': { 'two': { 'three': 'val' } } }

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 之前,我正在测试输出是否为string,如果不是,则使用"oops"。好吧,希望能有所帮助;祝你好运!

Playground link to code

答案 2 :(得分:-1)

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))

这适用于任何数量的嵌套。

{"one":{"two":{"three":{"four":{"five":{"six":"value"}}}}}}

我希望这就是你想要的