Typescript React:基于另一个道具类型的有条件可选道具 [英] Typescript React: Conditionally optional props based on the type of another prop

查看:20
本文介绍了Typescript React:基于另一个道具类型的有条件可选道具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试键入我正在处理的提取器组件 API.这个想法很简单,你给它一个 fetcher(promise 返回函数)和一个 params 数组(代表位置参数)作为 props,它会将结果提供给一个渲染道具.

type FunctionType= (...args: A) =>电阻类型参数= T extends FunctionType<infer R, any>?R : 从不类型 PromiseReturnType= T extends (...args: any[]) =>Promise<infer R>?电阻: 绝不类型 ChildrenProps<F>= {数据:PromiseReturnType}类型道具F= {取物者:F参数:参数<F>儿童:(道具:ChildrenProps<F>)=>React.ReactNode}类 Fetch扩展 React.Component<Props<F>{使成为() {返回空值}}常量用法 = (<div><Fetch fetcher={getUser} params={[{ id: 5 }]}>{({ 数据:用户 }) =>(<div>{user.name} {user.email}

)}</获取><Fetch fetcher={getCurrentUser} params={[]}>//<-- 冗余,因为 getCurrentUser 没有任何参数{({ 数据:用户 }) =>(<div>{user.name} {user.email}

)}</获取>

)

我想知道是否有一种方法可以说,如果 fetcher 函数不接受参数,则 params 属性不应该存在甚至是可选的?

我尝试如下修改道具,如果 fetcher 有 > 0 个参数,则只添加 params 字段

类型道具= {取物者:F儿童:(道具:ChildrenProps)=>React.ReactNode&(Arguments<F> extends []//没有参数?{}//无参数: {//和之前一样参数:参数<F>})

这实际上有效,但是现在在渲染道具中 data 字段不再正确输入.

{({ 数据:用户 }) =>(//数据:任何,但用户:从不...?<div>{user.name} {user.email}//名称/电子邮件在类型 never 上不存在

)}</获取>

我不知道为什么会这样.

<小时>

更新:

看来修改后的Props实际上是基于以下示例工作的

type PropsWithGetUser = Propstype PropsWithGetCurrentUser = Propsconst test1: PropsWithGetCurrentUser["children"] = input =>输入.数据.emailconst test2: PropsWithGetUser["children"] = input =>输入.数据.email

工作没有错误.

PropsWithGetUserPropsWithGetCurrentUser 的结果类型也被推断为以下似乎是正确的.

type PropsWithGetCurrentUser = {取物器:() =>承诺<用户>儿童:(道具:ChildrenProps<() => Promise>) =>React.ReactNode}输入 PropsWithGetUser = {取物器:({ID,}:{身份证号码},) =>承诺<用户>孩子们: (道具:ChildrenProps<({ID,}:{身份证号码},) =>承诺<用户>>,) =>React.ReactNode&{参数: [{身份证号码}]}

这个问题可能与我在 React 中使用它的方式有关吗?

解决方案

这在 TypeScript 3.0 中是可能的.

为了回答这个问题,我使用了 ArgumentTypes from
此答案:如何从 Typescript 中的函数获取参数类型.

方法如下:
TypeScript 操场上的演示

type ArgumentTypes=F extends (...args: infer A) =>任何 ?答:从不;type Props<F extends Function,参数 = ArgumentTypes<F>>=参数扩展{长度:0}?{取物器:F;} : {取物器:F;参数:参数};function runTest(props: Props) { }函数 test0() { }功能测试1(一:数字){}运行测试({取物器:test0//, params: []//错误});运行测试({取物器:test1//注释掉,//或者用无效的参数替换它//并查看错误, 参数: [1]});

I'm trying to type a fetcher component API that I'm working on. The idea is quite simple, you give it a fetcher (promise returning function) and a params array (representing the positional arguments) as props, and it will provide the results to a render prop.

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>
)

I was wondering if there was a way to say that if the fetcher function does not take arguments, the params prop should not be present or even optional?

I tried to modify the props as follows, only adding the params field if fetcher has > 0 arguments

type Props<F> = {
  fetcher: F
  children: (props: ChildrenProps<F>) => React.ReactNode
} & (Arguments<F> extends [] // no arguments
  ? {} // no params
  : { // same as before
      params: Arguments<F>
    })

Which actually works, however now in the render prop the data field is no longer typed correctly.

<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>

I'm not sure why this is the case.


UPDATE:

It seems that the modified Props is actually working from based on the following examples

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

that work without errors.

The resulting types of PropsWithGetUser and PropsWithGetCurrentUser are also inferred as the following which seems correct.

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
    }
  ]
}

Could the issue have something to do with the way I am using this with React?

解决方案

This is possible in TypeScript 3.0.

To answer the question, I used ArgumentTypes<F> from
this answer to: How to get argument types from function in Typescript.

Here's how:
Demo on 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]
});

这篇关于Typescript React:基于另一个道具类型的有条件可选道具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
其他开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆