如何从扩展接口推断泛型?

问题描述 投票:0回答:2

我有一个带有通用字段的界面,有点像

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
是否有一个类型签名可以返回正确的类型而不需要调用者指定它?

typescript interface narrowing
2个回答
1
投票

问题

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>

Playground 代码链接


0
投票

如果您需要一个遵循某些也具有泛型的接口的泛型,您也可以这样做:

interface Yeah<T> {
  val: T
}

function woo<T, U>(yeaher: T & Yeah<U>) {
  // ...
}
© www.soinside.com 2019 - 2024. All rights reserved.