Home > Software design >  why am I not getting the properties of my generic?
why am I not getting the properties of my generic?

Time:09-23

What I currently have, is a table, which is used in different components, which will have fixed sets of rows for targeting (QA automation), depending on where it is used.

I'm trying to make a generic of those rows for the table, but the code completion isn't working as intended. What am I missing?

class Base {
    protected myRoot : string
    constructor (root : string) {
        this.myRoot = root;
    }
    get base () {
        return "base getter"
    }
}
class FixedRows1 extends Base {
    get id1 () {
        return "id1"
    }
}
class FixedRows2 extends Base {
    get id2 () {
        return "id2"
    }
}
class FixedTable <T extends typeof Base> extends Base {
    private fixedRows : T
    constructor (inRoot : string, inFinalLayer : T) {
        super(inRoot)
        this.fixedRows = inFinalLayer
    }
    get rows () {
        return new this.fixedRows(this.myRoot)
    }
}

const layer = new FixedTable("root", FixedRows1);
layer.rows.base // <---- looking to be able to code complete `.example1`, but currently, only code completes `.base`

CodePudding user response:

The compiler tends to eagerly evaluate property accesses or function calls on unresolved generic types; that means when you write new this.fixedRows(this.myRoot), it widens this.fixedRows to its constraint of typeof Base, and thus returns Base. That's not wrong, but it doesn't have enough information for your purposes. If you want to change this, you'll probably need to assert that rows() returns something else:

get rows() {
  return new this.fixedRows(this.myRoot) as InstanceType<T>
}

Here I'm using the InstanceType<T> utility type to represent the type of the instance constructed by a constructor of type T.

Now it should behave the way you want:

const layer = new FixedTable("root", FixedRows1);
layer.rows.id1 // okay

Playground link to code

  • Related