在Typescript

时间:2018-02-01 00:05:50

标签: typescript

我在区分私人班级成员方面遇到了一些问题。我试图通过使用字符串文字访问变量v1v2,但是typescript返回一个类型联合。我设法解决了这个问题,给了打字稿一点“推”。坏消息是它只适用于公众成员。请参阅以下示例:

class Test {
    private v1: string;
    private v2: number;
    v3: string;
    v4: number;
    private v5: string;
    private v6: number;

    // Works for all members, but does not discriminate union
    get12(what: 'v1' | 'v2') {
        return this[what];
    }

    // Works only for public members
    get34<T extends 'v3' | 'v4'>(what: T) {
        return this[what];
    }

    // Explicit overload works, but it defeats the purpose of being lazy
    get56(what: 'v5'): string;
    get56(what: 'v6'): number;
    get56(what: 'v5' | 'v6') {
        return this[what];
    }
}

let myTest = new Test();
myTest.get12('v1'); // returns "string | number" type
myTest.get34('v3'); // returns "string" type
myTest.get56('v5'); // returns "string" type

有没有人知道某种解决方法?

修改 为了澄清,我正在寻找一个懒惰/通用的解决方案。还有其他方法可以实现我想要的,但是它们都需要我在变量类型更改的情况下维护它们(例如,显式重载)。

1 个答案:

答案 0 :(得分:3)

Bleggh,这似乎是TypeScript的design limitation,在某些具有私有属性的情况下,您无法使用索引访问。不知道如何最好地导航这个。

这是“有效”的东西,但我不能推荐实际做到这一点

//@ts-ignore
type UnsafeIndexed<T, K extends string> = T[K]

以上是一个故意错误的类型别名,要求编译器进行索引访问,即使它无法确定这样的事情是否有效。看看吧:

type Foo = { bar: string, baz: number };
type FooBar = UnsafeIndexed<Foo, "bar">; // string
type FooBaz = UnsafeIndexed<Foo, "baz">; // number
type FooBad = UnsafeIndexed<Foo, "nope">; // any

现在你可以这样做:

class Test {
    private v1: string;
    private v2: number;

    get<K extends 'v1' | 'v2'>(what: K): UnsafeIndexed<this,K> {
        return (this as any)[what];
    }
}

请注意,您必须执行(this as any),因为this[what]仍然会抛出编译器错误。测试一下:

let myTest = new Test();
const v1 = myTest.get('v1'); // string
const v2 = myTest.get('v2'); // number

好吧,就像我说的那样“有效”。但我不希望那些感人的生产代码。我不知道是否有一个较为邪恶的解决方法是通用的。就个人而言,我要么只使用公共属性或重载。您的里程可能会有所不同。

希望有所帮助。祝你好运!