【发布时间】:2018-10-12 13:15:40
【问题描述】:
我正在尝试键入我正在处理的提取器组件 API。这个想法很简单,你给它一个fetcher(promise 返回函数)和一个params 数组(表示位置参数)作为道具,它会将结果提供给渲染道具。
type FunctionType<A extends any[] = any[], R = any> = (...args: A) => R
type Arguments<T> = T extends FunctionType<infer R, any> ? R : never
type PromiseReturnType<T> = T extends (...args: any[]) => Promise<infer R>
? R
: never
type ChildrenProps<F> = {
data: PromiseReturnType<F>
}
type Props<F> = {
fetcher: F
params: Arguments<F>
children: (props: ChildrenProps<F>) => React.ReactNode
}
class Fetch<F> extends React.Component<Props<F>> {
render() {
return null
}
}
const usage = (
<div>
<Fetch fetcher={getUser} params={[{ id: 5 }]}>
{({ data: user }) => (
<div>
{user.name} {user.email}
</div>
)}
</Fetch>
<Fetch fetcher={getCurrentUser} params={[]}> // <-- Redundant since getCurrentUser doesn't have any params
{({ data: user }) => (
<div>
{user.name} {user.email}
</div>
)}
</Fetch>
</div>
)
我想知道是否有办法说如果 fetcher 函数不接受参数,则 params 属性不应该存在甚至是可选的?
我尝试修改props如下,如果fetcher有> 0个参数,只添加params字段
type Props<F> = {
fetcher: F
children: (props: ChildrenProps<F>) => React.ReactNode
} & (Arguments<F> extends [] // no arguments
? {} // no params
: { // same as before
params: Arguments<F>
})
这确实有效,但是现在在渲染道具中,data 字段不再正确输入。
<Fetch fetcher={getUser} params={[{ id: 5 }]}>
{({ data: user }) => ( // data: any, yet user: never...?
<div>
{user.name} {user.email} // name / email does not exist on type never
</div>
)}
</Fetch>
我不知道为什么会这样。
更新:
看起来修改后的Props实际上是基于以下示例工作的
type PropsWithGetUser = Props<typeof getUser>
type PropsWithGetCurrentUser = Props<typeof getCurrentUser>
const test1: PropsWithGetCurrentUser["children"] = input => input.data.email
const test2: PropsWithGetUser["children"] = input => input.data.email
可以正常工作。
PropsWithGetUser 和 PropsWithGetCurrentUser 的结果类型也被推断为以下似乎正确的类型。
type PropsWithGetCurrentUser = {
fetcher: () => Promise<User>
children: (props: ChildrenProps<() => Promise<User>>) => React.ReactNode
}
type PropsWithGetUser = {
fetcher: (
{
id,
}: {
id: number
},
) => Promise<User>
children: (
props: ChildrenProps<
(
{
id,
}: {
id: number
},
) => Promise<User>
>,
) => React.ReactNode
} & {
params: [
{
id: number
}
]
}
这个问题可能与我在 React 中使用它的方式有关吗?
【问题讨论】:
-
是的,您的更新有效,因为类型已经解析,问题是当您要求编译器同时推断时..
-
其他人可能会证明我错了(我希望他们这样做),但我认为你不能比明确指定函数类型做得更好,即:
<Fetch<typeof getUser> fetcher={getUser} params={[{ id: 5 }]}> -
谢谢,Meligy 的回答似乎通过使用另一个类型参数来解决这个问题。你知道我的方法行不通的根本原因吗?还是它只是打字稿实现方式的一部分?
-
不,这似乎很好,嫉妒我自己没想到:-P
标签: reactjs typescript