Constrain keys that are part of looked-up type

41 Views Asked by At

I need to create a constraint that limits keys of TP1 listed by the keyof keyword to properties that are of a specific type. When I use the builder.setMetadata method, the first parameter should not accept string "configure" as a valid value (it should accept foo and other keys that are typed as Foo<something>). I've tried to come up with a solution by myself, but I'm a bit lost and have been doing it for more than three hours now. Following is the working code:

interface Foo<T> {};

class Test { prop: string; }

class Builder<T> {
    public setMetadata<TP1 extends keyof this, TP2 extends keyof this[TP1]>(prop: TP1, propOfProp: TP2) {
        // ...
    }
}

class Bar {
    foo: Foo<Test>;

    configure(builder: Builder<Bar>) {
        builder.setMetadata("", ""); // only "foo" should be accepted value in the first argument, "configure" shouldn't be in the list
    }
}
2

There are 2 best solutions below

0
On

Solved it by myself using a function:

function createInstance<T extends Function & { [P in keyof TSchema]: Foo<any> }>(schema: T, configure: (builder: Builder<T["prototype"]>) => void): any {
    // ...
}
3
On

How about this?

class Builder<T> {
  public setMetadata<TP1 extends keyof T, TP2 extends T[TP1]>(prop: TP1, propOfProp: TP2) {
    // ...
  }
}

class BarData {
  foo: Foo<Test>;
}

class Bar extends BarData {
  configure(builder: Builder<BarData>) {
    // ...
  }
}

I made changes in a few places:

  • use T instead of this in setMetadata's type
  • don't use keyof in setMetadata's second param type
  • move foo into a separate class