简体   繁体   English

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

[英]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 splitreduce似乎是解决这个问题的方法,但我还没有使用下面的代码让它工作

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]nullundefined以便在传递错误字符串时代码不会抛出运行时错误。

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是任何objectpath是任何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而不是一个undefinedstring ,这是您传入时会发生的情况,例如, "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!祝你好运!

Playground link to code Playground 链接到代码

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM