我有一个带有通用字段的界面,有点像
interface HasVal<T> {
val: T
}
我想创建一个像
get_val
这样的函数,它接受任何 HasVal
实现者并返回它的 val:
function get_val<T, Hv extends HasVal<T>>(hv: Hv): T {
return hv.val
}
这不起作用,因为 T 由于某种原因没有缩小:
class MyVal {
val = "hello world!"
}
let u = get_val(new MyVal());
// type of u is unknown :(
get_val
是否有一个类型签名可以返回正确的类型而不需要调用者指定它?
问题
declare function get_val<T, Hv extends HasVal<T>>(hv: Hv): T;
是通用约束不用作其他通用类型参数的推理站点。 (此类功能曾在 microsoft/TypeScript#7234 中提出,但最终被拒绝,转而采用其他技术。)因此,虽然
Hv
可以从 hv
参数中推断出来,但 T
不能从 Hv extends HasVal<T>
中推断出来约束。几乎没有地方可以推断出 T
,因此它会退回到隐式 unknown
约束,并且您会得到不良行为。
鉴于此示例,我倾向于完全删除
Hv
类型参数。如果您想从 T
类型的输入推断 HasVal<T>
,请直接告诉编译器 hv
是 HasVal<T>
类型,而不是通过约束间接地:
function get_val<T>(hv: HasVal<T>): T {
return hv.val
}
现在事情按预期进行:
let u = get_val(new MyVal());
// let u: string
T
被推断为 string
,因为 MyVal
实例被视为有效的 HasVal<string>
。
如果您需要一个遵循某些也具有泛型的接口的泛型,您也可以这样做:
interface Yeah<T> {
val: T
}
function woo<T, U>(yeaher: T & Yeah<U>) {
// ...
}