如何覆盖对象字段并使IDE看到它?

时间:2019-03-25 15:03:09

标签: javascript typescript autocomplete webstorm

我有一个带有一些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();

没有幻想:智能感知向我展示了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-不能,而且无论如何,我希望它能更深入地工作。

有可能吗?

//已添加 谢谢,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

1 个答案:

答案 0 :(得分:0)

问题解决了。

需要声明类型:

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;
...