Francisco Santorelli
Francisco Santorelli

Reputation: 1338

Have Class<T extends { [key: string]: any }> implement T

I have an injectable Class<T extends { [key: string]: any }> which has the purpose of obtaining a Generic Object. Such as:

interface Home {
  darkTheme: boolean;
  userType: number;
}

and then I would inject my class like:

constructor(myClass: Class<Home>) {}

this works great for some methods that live inside my class. However, I want the class to be aware that its body has the keys of T as properties also. In a way that this:

const userType = this.myClass.userType // acknowledges it exists

is ok by typescript.

TS doesn't throw an error with this, and userType would get the desired value. But this happens with Typescript being ignorant that the property exists in the body of myClass.

So how can I tell Typescript that myClass<T> has a body T?

I have tried:

class myClass<T extends { [key: string extends keyof T]: any}> // nope

class myClass<T extends { [key: string]: any } implements/ extends T> // also nope

// I tried overloading
interface myClass<T extends { [key: string]: any }> {
  [key: K keyof T]: T[K]; // don't know what 'K' is;
}

interface myClass<T extends { [key: string]: any }> {
  [key: keyof T]: T[keyof T]; // interfaces don't like mapped types
}

and little more. If you have any idea how can I achieve this, or if it's possible at all, I'd be happy to read you! :D thanks.

Upvotes: 2

Views: 2254

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250106

Typescript does not support extending the type parameter directly. Depending on what you are trying to do, you can either use a type alias:

type Class<T> = T & {}
declare let myClass: Class<Home>
myClass.userType // works, and is checked
myClass.userTypes // err

Or you can define your class without the explicit T and then cast it as a constructor that returns something that also has the properties of T:

class _Class { 
    m() { }
}

const Class = _Class as (new <T>() => _Class & T);  
type Class<T> = T & _Class
let myClass = new Class<Home>()
myClass.m(); //ok
myClass.darkTheme // ok

Upvotes: 3

Related Questions