如何解决在推断泛型类型时避免扩展
使用此示例功能
type Decoder<A,B> = (v: A) => B
declare function test<Values,D extends Decoder<Values,unknown>>(options: {
values: Values,decoder: D,onDecoded: (decodedValue: ReturnType<D>) => unknown
}): void;
这个想法是onDecoded
输入decoder
计算得到的值。但是:
test({
values: { a: "" },decoder: values => values.a.length,onDecoded: decodedValue => {
decodedValue // unknown
}
})
奇怪的是,如果我在values
的定义中没有使用decoder
,那么decodedValue
的类型正确
test({
values: { a: "" },decoder: () => 42,onDecoded: decodedValue => {
decodedValue // number
}
})
这是一个带有相同示例的playground link
有没有办法使原始示例正常工作?
解决方法
这里的问题是编译器在推断所有内容之前就放弃了。您只有一个对象,编译器需要从该对象推断两个类型参数,但无法一次完成所有操作。
首先,让我将您的签名重构为几乎等效的版本,以使其更易于分析:
declare function test<A,B>(options: {
values: A,decoder: (a: A) => B,onDecoded: (b: B) => unknown
}): void;
与您的版本具有相同的推断问题,但是谈论类型要容易一些。无论如何,编译器需要从您想从中推断出A
和B
的{{1}}值密码中推断出options
和A
。它可以从B
的类型推断出A
,但是除非values
的实现不依赖于B
,否则可能无法推断出decoder
,所以失败了。
类型推断的细节不是我的专家。但是,如果对此问题有一个规范的答案,那就是microsoft/TypeScript#38872,它使用非常相似的数据结构并遇到相同的问题。这在TypeScript中被归类为设计限制,因此在不更改A
函数或调用方式的情况下,可能无法解决此问题。
更改您的调用方式将涉及向编译器提供足够的类型信息,以使其能够工作。例如,如果在调用时注释test
的输入参数的类型,就可以了:
decoder
或者您可以更改test({
values: { a: "" },decoder: (values: { a: string }) => values.a.length,// annotate
onDecoded: decodedValues => {
decodedValues // number
}
})
的定义方式。我的一个建议是将test()
对象拆分为单独的参数。相比于单个参数,编译器更愿意为不同的函数参数花费多个推理过程。也许像这样:
options
这些推论完全按照您想要的方式工作,您可以根据需要使用declare function test2<A,B>(values: A,onDecoded: (b: B) => unknown
): void;
test2(
{ a: "" },values => values.a.length,decodedValues => {
decodedValues // number
}
)
test2({ a: "" },() => 42,decodedValues => {
decodedValues // number
}
)
和D
重写它们。
我猜你想走哪条路。无论如何,希望能有所帮助;祝你好运!
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。