打字稿。如何从其值获取对象的属性名称?

时间:2016-05-05 10:32:35

标签: javascript typescript immutable.js

我正在编写一个与immutable map

一起使用的打字稿类
class NavigableObject<T> {
    constructor(private obj: T, private path: string[] = []) { }

    To<R>(p: (x: T) => R): NavigableObject<R> {
        return new NavigableObject<R>(p(this.obj),
                       this.path.concat(this.getPropName(p(this.obj))));
    }

    getPath() {
        return this.path;
    }

    private getPropName(value) {
        for (var item in this.obj) {
            if (this.obj[item] === value) {
                return item;
            }
        }
    }
}

let test = {
    a: {
        a1: 1,
        a2: 1
    },
    b: {
        b1: 1,
        b2: 2
    }
}

let navigableTest = new NavigableObject(test);

navigableTest.To(m => m.b).To(m => m.b2).getPath(); // = ["b", "b2"]

navigableTest.To(m => m.a).To(m => m.a2).getPath(); // = ["a", "a1"] <-- I selected a2, tho

getPropName方法存在问题。当obj具有两个具有相同值的属性时,只会匹配第一个属性。

有谁知道如何解决这个问题?

4 个答案:

答案 0 :(得分:3)

您可以使用this way of getting the property name

class NavigableObject<T> {
    constructor(private obj: T, private path: string[] = []) { }

    To<R>(p: (x: T) => R): NavigableObject<R> {
        return new NavigableObject<R>(p(this.obj),
                       this.path.concat(this.getPropName(p)));
    }

    getPath() {
        return this.path;
    }

    private static propertyRegEx = /\.([^\.;]+);?\s*\}$/;

    private getPropName(propertyFunction: Function) {
        return NavigableObject.propertyRegEx.exec(propertyFunction.toString())[1];
    }
}

let test = {
    a: {
        a1: 1,
        a2: 1
    },
    b: {
        b1: 1,
        b2: 2
    }
}

let navigableTest = new NavigableObject(test);

navigableTest.To(m => m.b).To(m => m.b2).getPath(); // = ["b", "b2"]

navigableTest.To(m => m.a).To(m => m.a2).getPath(); // = ["a", "a2"]

答案 1 :(得分:2)

使用您当前的查询方法,您无法轻松完成任务。你选择哪种属性是不明确的,所以要找到正确的道路并不容易。这并不是说你的代码是错误的&#39;现在,这只是两个可能的正确答案,而且它是任意选择的。

您可以更改其选择的可能键的规则,但没有合理的规则可以可靠地为您提供正确的单一答案。或者你可以返回所有可能的答案,并且有一个模棱两可的路径,但它看起来并不像你正在寻找的那样。

可能有一个选项可以做一些疯狂的事情,例如解析Esprima提供的功能,甚至是正则表达式来解决抓取哪些属性,但这通常是一个坏主意。这可能是复杂而脆弱的,不可靠,除非您能保证To()中提供的代码的确切形状,并且运行得非常慢。

如果您确实希望能够选择这样的属性并知道确定的路径,那么您必须为您的To函数提供属性的关键字,而不仅仅是获取的函数它拥有的价值。它是一个不太优雅的API,但它是您获得您正在寻找的行为的唯一合理方式:

class NavigableObject<T> {
    constructor(private obj: T, private path: string[] = []) { }

    To<R>(p: string): NavigableObject<R> {
        return new NavigableObject<R>(this.obj[p],
                       this.path.concat(p));
    }

    getPath() {
        return this.path;
    }
}

let test = {
    a: {
        a1: 1,
        a2: 1
    },
    b: {
        b1: 1,
        b2: 2
    }
}

let navigableTest = new NavigableObject(test);

navigableTest.To('b').To('b2').getPath();

navigableTest.To('a').To('a2').getPath();

将来有可能在TypeScript中使用类型安全性,但现在不行。 This PR正在研究这些问题,但目前还在进行一些讨论,所以在实施之前还有一段时间。请注意,它仍在提出上述示例中基于字符串的方法,只是类型系统将检查字符串常量是否为所用类型的有效属性名称。

答案 2 :(得分:1)

未来就在这里。根据Tim Perry的link,TypeScript现在添加了keyof,这是获取类的可用属性的一个很棒的功能。

根据TypeScript documentation的用法:

interface Person {
    name: string;
    age: number;
    location: string;
}

type K1 = keyof Person; // "name" | "age" | "location"
type K2 = keyof Person[];  // "length" | "push" | "pop" | "concat" | ...
type K3 = keyof { [x: string]: Person };  // string

答案 3 :(得分:0)

不要在找到的第一个值上终止for,并返回具有匹配值的名称数组。我告诉你如何处理多个名字的问题。

private getPropName (value) {
    var items = [];
    for (var item in this.obj) {
        if (this.obj[item] === value)
            items.push (item);
    return items;
}
相关问题