我有一些带有一些State属性的类,我通过一些函数格式化State的字段:
function DoMagic(prototypeObj: any) : any;
因此,功能“DoMagic”将对象变为:
const Foo = {
ID: -1,
Name: '',
Something: [1,2,3]
}
至
const Bar = {
ID: {
get Value(){return Foo.ID;},
},
Name: {
get Value(){return Foo.ID;},
},
Something: {
0: {get Value(){return Foo.Something[0]} },
1: {get Value(){return Foo.Something[1]} },
2: {get Value(){return Foo.Something[2]} },
}
};
它运行正常,但是当Foo是类属性时,我想让WebStorm的自动完成提供Bar的属性而不是Foo。
如果我做的事情
type ClassState = {
ID: number;
Name: string;
Something: number[]
}
class Class1{
State: ClassState = {
ID: -1,
Name: '',
Something: [1,2,3],
};
constructor(){
Object.defineProperty(this, 'State', DoMagic(this.State))
}
}
let instance = new Class1();
并没有错觉:当然,intellisense会向我展示ClassState的属性。
我得到它的最接近的方式 - 定义一些自定义类型并声明自己的“接口”,如下所示:
class TypesBase {
protected _Value: any;
get Value():any {return this._Value};
}
class TypeInt extends TypesBase{
get Value() : number {return this._Value};
}
class TypeString extends TypesBase{
get Value() : string {return this._Value};
}
class TypeArray<T> extends TypesBase{
get Value() : T[] {return this._Value};
}
class Class2 {
State = {
ID: new TypeInt(),
Name: new TypeString(),
Something: new TypeArray<number>(),
};
StateData = {
ID: -1,
Name: '',
Something: [1,2,3],
};
constructor(){
Object.defineProperty(this, 'State', DoMagic(this.StateData))
}
}
let inst2 = new Class2();
它适用于像inst2.ID.Value
这样的简单字段,但inst2.Something[0].Value
- 没有,而且,无论如何,我希望它能更深入地工作。
有可能吗?
// ADDED谢谢,jcalz,这种方式更清洁
type Magic<T> = {[K in keyof T]: any | {Value: T[K]}};
class Class2 {
State: Magic<ClassState> = {
ID: -1,
Name: '',
Something: [1,2,3],
};
...
但是如何让它更深层次?喜欢:
inst2.Something[0].Value
inst2.Something[0].DeeperLevelObject.Value
问题解决了。
需要声明类型:
type Simple<T> = {Value: T};
type MagicArray<T, U> = {
[Key: number]: Simple<U>;
Value: T
}
type Magic<T> = Simple<T>
&
{ readonly [K in keyof T]:
T[K] extends (infer ElementType)[] ? MagicArray<T[K], ElementType>:
T[K] extends object ? Magic<T[K]> :
Simple<T[K]>
}
使用:
type ClassState2 = {
Field1: number;
Field2: string;
};
type ClassState = {
ID: number;
Name: string;
SomeArr: number[];
SomeObj: ClassState2;
SomeObjArr: ClassState2[];
};
const SomeState : Magic<ClassState> = null;
//now SomeState can get autocomplete with proper types:
SomeState.Value;
SomeState.ID.Value;
SomeState.SomeArr[0].Value;
SomeState.SomeObjArr[0].Field1.Value;
...