我在区分私人班级成员方面遇到了一些问题。我试图通过使用字符串文字访问变量v1
和v2
,但是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
有没有人知道某种解决方法?
修改 为了澄清,我正在寻找一个懒惰/通用的解决方案。还有其他方法可以实现我想要的,但是它们都需要我在变量类型更改的情况下维护它们(例如,显式重载)。
答案 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
好吧,就像我说的那样“有效”。但我不希望那些感人的生产代码。我不知道是否有一个较为邪恶的解决方法是通用的。就个人而言,我要么只使用公共属性或重载。您的里程可能会有所不同。
希望有所帮助。祝你好运!