The compiler complains that you did not establish a direct relationship between the return type of the getValue
function and the data
instance property. extends
clause only guarantees that at a minimum the generic type parameter is assignable to the provided constraint, but does not bound it otherwise.
Moreover, your getValue
function returns a constant of type { key : 'value' }
. Therefore, when you assign the return type of a call to getValue
to this.data
, the compiler looks if the latter is a supertype of the former and sees that you only guaranteed data
to be { [key: string]: any }
, or, in plain English:
"some kind of object with any number of keys of type string and values of any type"
It should be obvious that data
can have nothing in common with the { key : 'value' }
type. Now, take a look at what happens if you explicitly tell the compiler that T
should conform to the return type of the getValue
instead:
class Foo<T extends {[key: string]: any}> {
public readonly data?: T | ReturnType<typeof getValue>;
constructor() {
this.data = getValue(); //OK
}
}
Now the compiler is happy because it can establish the relationship, but you become limited to objects with single key key
and values of type string
. Frankly, from your snippet, it is unclear why do you need to make the class generic at all:
class Foo {
public readonly data?: ReturnType<typeof getValue>;
constructor() {
this.data = getValue(); //OK
}
}