假设我们有以下代码:
// a value, and a function that will be called with this value
type ValueAndHandler<T> = [value: T, handler: (value: T) => void]
type Params = {
// not sure how to type it
valuesAndHandlers: ValueAndHandler<???>[]
// it's not the only field in the structure
// so I cannot just pass array as variadic arguments
otherStuff: number
}
function doSomethingWithParams(params: Params){/* something, not important*/}
doSomethingWithParams({
// array of some pairs of handlers and values
// each value is only related to its handler, and not to other handlers/values
valuesAndHandlers: [
[5, value => console.log(value.toFixed(3))],
["example", value => console.log(value.length)]
],
otherStuff: 42
})
在这段代码中,我希望第一个处理程序的参数类型被推断为number
,第二个处理程序的参数类型被推断为string
;但这并没有发生(因为我在变量定义中将它们输入为unknown
)。
如何键入定义以便分别推断每个处理程序的正确类型?
我尝试为泛型参数添加一个默认类型,但没有帮助,因为它对所有对都是一样的。我还尝试使用satisfies
,而不显式输入变量,但效果一样。我也见过this question,但无法将该技术应用于我的情况。
2条答案
按热度按时间wz3gfoph1#
如果你想要像这样的推断,你没有太多的选择,除了旋转一个 Package 器fn:
sauutmhj2#
假设你真的想跟踪数组中每个元素的generic类型参数的元组,那么你必须在该元组类型中使
Params
成为泛型:这里的
valuesAndHandlers
属性是一个Map的元组类型,其中输入类型T
的每个元素T[I]
(在索引I
处)都被ValueAndHandler
Package 成ValueAndHandler<T[I]>
。这并没有真正改变类型,但它确实给予了编译器一个提示,即当它推断类型时,它应该尝试推断元组而不是无序的任意长度数组类型(这在microsoft/TypeScript#39094:“[...T]
类型,其中T
是一个类似数组的类型参数,可以方便地用于指示元组类型推断的首选项”)。为了减少需要编写的类型注解的数量,我们可以创建一个helper函数来推断特定的
T
参数,给定一些Params<T>
:我们可以这样使用它:
因此,
params
被推断为Params<[number, string]>
。请注意,为了使它工作,我必须在回调中注解参数类型,这种从上下文推断
value => console.log(value.length)
中value
类型的上下文类型不适用于从属性内部Map元组的推断。根据您的关注程度,可以通过重构asParams()
函数以接受valuesAndHandlers
属性值作为单独的参数来减轻这种情况......或者实际上,任何数量的可能的重构来调整推断。这里的主要概念点是
Params
需要是通用的,其余部分主要是尝试获得所需推断的技术。Playground链接到代码