Lio*_*Tay 6 typescript reactjs
我正在尝试输入正在使用的提取程序组件API。这个想法很简单,给它一个fetcher(承诺返回函数)和一个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>
)
Run Code Online (Sandbox Code Playgroud)
我想知道是否有一种方法可以说,如果fetcher函数不带参数,则params道具应该不存在甚至是可选的?
我尝试如下修改道具,仅在参数> 0时添加params字段fetcher
type Props<F> = {
fetcher: F
children: (props: ChildrenProps<F>) => React.ReactNode
} & (Arguments<F> extends [] // no arguments
? {} // no params
: { // same as before
params: Arguments<F>
})
Run Code Online (Sandbox Code Playgroud)
实际上有效,但是现在在渲染道具中,该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>
Run Code Online (Sandbox Code Playgroud)
我不确定为什么会这样。
更新:
看来修改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
Run Code Online (Sandbox Code Playgroud)
没有错误的工作。
产生的类型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
}
]
}
Run Code Online (Sandbox Code Playgroud)
问题可能与我在React中使用它的方式有关吗?
这在 TypeScript 3.0 中是可能的。
为了回答这个问题,我使用了ArgumentTypes<F>这个
答案:How to get argument types from function in Typescript。
操作方法如下:
在 TypeScript Playground 上进行演示
type ArgumentTypes<F extends Function> =
F extends (...args: infer A) => any ? A : never;
type Props<F extends Function,
Params = ArgumentTypes<F>> =
Params extends { length: 0 } ?
{
fetcher: F;
} : {
fetcher: F;
params: Params
};
function runTest<F extends Function>(props: Props<F>) { }
function test0() { }
function test1(one: number) { }
runTest({
fetcher: test0
// , params: [] // Error
});
runTest({
fetcher: test1
// Comment it,
// or replace it with invalid args
// and see error
, params: [1]
});
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
2243 次 |
| 最近记录: |