我试图为函数myFunction
创建类型设置,但返回的类型不正确。
type Base = {
[key: string]: (state: any, payload: {
type: any
payload?: any
}) => any
}
const myFunction = <T extends Base>(arg: T) => {
return {
actions: {} as {
[Key in keyof T]: {
[K in Parameters<T[Key]>[1]['type']]: (arg: Parameters<T[Key]>[1] & { type: K }) => void
}
}
}
}
const reducer1 = (state: boolean, payload: { type: 'foo', payload: number } | { type: 'batman' }) => state
const reducer2 = (state: string, payload: { type: 'bar' }) => state
const {actions} = myFunction({
domain1: reducer1,
domain2: reducer2
})
返回的actions
对象应该有两个属性domain1
和domain2
,每个域应该有相应的函数。
但是我似乎不能得到正确的函数参数:
actions.domain1.batman() // no argument should be required
actions.domain1.foo() // argument should be number
actions.domain2.bar() // no argument should be required
看看这个Playground。
2条答案
按热度按时间jdgnovmf1#
这里的主要问题是
(Parameters<T[Key]>[1] & { type: K })
将具有type
和payload
属性,因此(arg: Parameters<T[Key]>[1] & { type: K }) => void
将需要该类型的输入。但是您实际上希望输入只是payload
属性。这意味着你只是忘记了用"payload"
将index转换成该类型:这将为您提供以下理想行为:
但是你仍然会遇到没有
payload
的类型需要一个参数的情况:它需要一个
unknown
类型的参数,因为像{type: "batman"}
这样的类型没有已知的payload
属性,所以实际上任何类型都可以在这样的索引中。相反,我认为你想要的是,如果
payload
可能是undefined
,那么你希望arg
是一个可选参数。我们可以编写一个实用程序类型,如其使用conditional type在两种类型的功能之间切换。然后我们使用它:
现在你得到了你想要的行为:
这基本上是对所问问题的回答。请注意,我们可以简化mapping over
Parameters<T[Key]>[1]["type"]
的技术,然后在另一边提取相应的联合成员。您可以通过使用键重Map来迭代Map类型中的任意联合。因此,我们可以迭代
Parameters<T[Key]>[1]
,而不是Parameters<T[Key]>[1]["type"]
,然后直接提取type
作为键,payload
作为值:这不会改变结果类型:
但它更简单。
Playground链接到代码
eyh26e7m2#
接受的答案是伟大的,但我遇到了一个问题,如果所有的有效载荷是mandetory。
看看这个Playground。
我目前正在寻找解决方案。
更新:似乎从
Base
类型中删除?
解决了它...?更新的Playground在这里。