简体   繁体   English

推断 object 的属性传递给 class 构造函数(打字稿)

[英]Infer properties of object passed to class constructor (typescript)

I have the following situation:我有以下情况:

abstract class A {
    obj;

    constructor(obj:{[index:string]:number}) {
        this.obj = obj;
    }
}

class B extends A {
    constructor() {
        super({i:0})
    }

    method() {
        //Here I would like intellisense to only suggest this.obj.i
    }
}
class C extends A {
    constructor() {
        super({i:0,j:0})
    }

    method() {
        //Here I would like intellisense to only suggest this.obj.i and this.obj.j
    }
}

I would like in class B to get autocompletion for the object passed in the constructor and likewise for class C .我想在class B中自动完成在构造函数中传递的 object 和class C Is there a way to do this, or am I doing something fundamentally wrong here?有没有办法做到这一点,还是我在这里做一些根本错误的事情?

You can try using generic A class like this:您可以尝试像这样使用generic A class :

abstract class A<T extends Record<string, number> = Record<string, number>> {
    obj: T;

    constructor(obj:T) {
        this.obj = obj;
    }
}

class B extends A<{ i: number }> {
    constructor() {
        super({i:0})
    }

    method() {
        //Here I would like intellisense to only suggest this.obj.i
    }
}
class C extends A<{ i: number, j: number }> {
    constructor() {
        super({i:0,j:0})
    }

    method() {
        //Here I would like intellisense to only suggest this.obj.i and this.obj.j
    }
}

Play here 在这里

Playground Two ways to do this, it has to do with utilizing generics Playground有两种方法可以做到这一点,它与利用 generics 有关

  • method one, a slightly simpler generic on abstract class A yields方法一,抽象 class A 上的一个稍微简单的泛型产生
abstract class A<T extends number extends infer U ? U : number> {
    obj;

    constructor(obj:{[index:string]:T}) {
        this.obj = obj;
    }
}

class B extends A<0> {
    constructor(public readonly i: number extends infer U ? U : number) {
        super({i:0});
        this.i.valueOf() in super.obj;
        /**
         Inferred value when cntrl+hover super

         constructor A<0>(obj: {
            [index: string]: 0;
          }): A<0>
         */
    }

    truthyMethod() { 
      console.log(super.obj)
     const superObjEqualsObjCreate = super.obj === Object.create({ i: this.i }) ? true : false;
     console.log(superObjEqualsObjCreate);
     return superObjEqualsObjCreate
      /**
       * Here intellisense only suggests the result of i
        (property) A<0>.obj: {
          [index: string]: 0;
        }
       */
    }
}
class C extends A<3.14> {
    constructor() {
        super({i:3.14,j:3.14})
    }

    method() {
          const superObjEqualsObjCreate =  super.obj === this.obj ? true : false;
          console.log("C: " + superObjEqualsObjCreate)
          return superObjEqualsObjCreate;
        //(property) A<3.14>.obj: {
   //       [index: string]: 3.14;
//        }
    }
}

This next approach is my preference, slightly more complex for the generic but a much more concise super inference下一种方法是我的偏好,对于通用但更简洁的super推理稍微复杂一些

If you want to pass different values to each key in your super objects then you can use A<number> when extending the abstract class A (otherwise they have to be constant -- a union of numbers or floats would work as well)如果您想将不同的值传递给超级对象中的每个键,则可以在扩展抽象 class A 时使用A<number> (否则它们必须是恒定的——数字或浮点数的联合也可以)

abstract class A<T extends number extends {[index: string]: infer U} ? U : number> {
    obj;

    constructor(obj:Record<string, T>) {
        this.obj = obj;
    }
}

class B extends A<0> {
    constructor(public readonly i: number extends infer U ? U : number) {
        super({i:0});
        //  Inferred value when cntrl+hover super
        // constructor A<0>(obj: Record<string, 0>): A<0>
         
    }

    stringify() { 
      return JSON.stringify({ 
        i: this.i, // i: number
        sup: super.obj // sup: { [x: string]: 0; }
      }, null, 2);
      
        // Here intellisense only suggests the result of i
        // (property) A<0>.obj: {
        //   [index: string]: 0;
        // }
       
    }
}

class C extends A<3.14 | -7.28> {
    constructor() {
        super({i:3.14,j:-7.28})
        // super inferred:
        // constructor A<3.14 | -7.28>(obj: Record<string, 3.14 | -7.28>): A<3.14 | -7.28>
    }

    method() {
      super.obj === this.obj ? true : false;
        //Here I would like intellisense to only suggest this.obj.i and this.obj.j
    }
}


console.log(new B(12).stringify()); // B is dynamic, accepts args
console.log(new C()) // C is static

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM