Leo Jiang
Leo Jiang

Reputation: 26075

Typescript 'keyof InstanceType<T>' cannot be used to index type error

Here's the sample code:

class Base {}

function fn<T extends typeof Base>(
    Cls: T,
    prop: keyof InstanceType<T>,
) {
    return (new Cls())[prop];
}

TS Playground: https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCkFNoG8C+AodAzArgO2ABcBLAez2izwB4AVaBAD0ITwBMZCBPABwVKxxEAPgAU6aJOgBhEBABc0WgBoJUngCdSPRQGsEXAdACSeCITAEEtXgjrDVAShRrJGhIRwaKovAgDuMnKijo4A2praALoA3OgYQA

prop should be a property on Cls, yet this code doesn't work?

It works if I change keyof InstanceType<T> to keyof Base, but I want the function to work with any subclass of Base.

Upvotes: 3

Views: 903

Answers (4)

It is doable:

class Base {
  base = 'base'
}

class A extends Base {
  a = 'a'
}
class B extends Base {
  b = 'b'
}

class C {
  c = 'c'
}


const fn = <
  T extends typeof Base,
  Instance extends InstanceType<T>
>(Cls: new () => Instance, prop: keyof Instance,
) => new Cls()[prop];

const result = fn(A, 'base') // ok

const result2 = fn(B, 'b') // ok

const result3 = fn(Base, 'base') // ok

const result4 = fn(A, 'b') // expected error

const result5 = fn(B, 'a') // expected error

const result6 = fn(C, 'x') // expected error

Upvotes: 1

Alireza Ahmadi
Alireza Ahmadi

Reputation: 9893

There is no need to new Cls And InstanceType Try this one:

class Base {}

function fn<T extends typeof Base>(Cls: T,prop: keyof T) {
     return Cls[prop];
}

Upvotes: 0

Nishant
Nishant

Reputation: 55856

There is a couple of problems here:

class Base {}

function fn<T extends typeof Base>(
    Cls: T, // <--- Cls is already an instance of T
    prop: InstanceType<T>, // <-- if you want properties of the class use keyof T
) {
    return (new Cls())[prop]; // <-- You cannot call new on instance
}

With these in mind, this may work for you:

class Base {}

function fn<T extends Base>(
    Cls: T,
    prop: keyof T,
) {
    return Cls[prop];
}

TS Playground: https://tsplay.dev/WJ9DDm

However, if you are passing the class to fn and not the instance, the answer by Wang Weixuan fits better.

Upvotes: 0

Wang Weixuan
Wang Weixuan

Reputation: 351

It seems that TypeScript compiler reacts badly when InstanceType is used on generics.

It works if you change the generic parameter to the instance type, which should be equivalent to original code:

function fn<T extends Base>(
    Cls: new () => T, 
    prop: keyof T
) {
    return new Cls()[prop];
}

Upvotes: 2

Related Questions