I have an interface with a generic field, sort of like
interface HasVal<T> {
val: T
}
I want to create a function like get_val
which accepts any HasVal
implementer and returns it's val:
function get_val<T, Hv extends HasVal<T>>(hv: Hv): T {
return hv.val
}
This doesn't work, because T doesn't get narrowed for some reason:
class MyVal {
val = "hello world!"
}
let u = get_val(new MyVal());
// type of u is unknown :(
Is there a type signature for get_val
that will return the proper type without requiring the caller to specify it?
The problem with
declare function get_val<T, Hv extends HasVal<T>>(hv: Hv): T;
is that generic constraints are not used as inference sites for other generic type arguments. (Such a feature was suggested at microsoft/TypeScript#7234 but eventually declined in favor of other techniques.) So while Hv
can be inferred from the hv
argument, T
cannot be inferred from the Hv extends HasVal<T>
constraint. There's pretty much nowhere from which T
can be inferred, so it falls back to the implicit unknown
constraint, and you get the undesirable behavior.
Given this example, I'd be inclined to just remove the Hv
type parameter entirely. If you want to infer T
from an input of type HasVal<T>
, tell the compiler that hv
is of type HasVal<T>
directly, not indirectly via a constraint:
function get_val<T>(hv: HasVal<T>): T {
return hv.val
}
And now things behave as desired:
let u = get_val(new MyVal());
// let u: string
T
is inferred as string
because a MyVal
instance is seen as a valid HasVal<string>
.