简体   繁体   English

打字稿反应:根据另一个道具的类型有条件地选择道具

[英]Typescript React: Conditionally optional props based on the type of another prop

I'm trying to type a fetcher component API that I'm working on. 我正在尝试键入我正在处理的fetcher组件API。 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. 这个想法很简单,你给它一个fetcher (承诺返回函数)和一个params数组(表示位置参数)作为props,它将结果提供给渲染道具。

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? 我想知道是否有办法说如果fetcher函数不接受参数, params prop不应该存在甚至是可选的?

I tried to modify the props as follows, only adding the params field if fetcher has > 0 arguments 我尝试修改道具如下,如果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>
    })

Which actually works, however now in the render prop the data field is no longer typed correctly. 这实际上有效,但现在在渲染道具中, 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>

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 似乎修改后的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

that work without errors. 这工作没有错误。

The resulting types of PropsWithGetUser and PropsWithGetCurrentUser are also inferred as the following which seems correct. 结果类型的PropsWithGetUserPropsWithGetCurrentUser也被推断为以下似乎是正确的。

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? 这个问题可能与我在React中使用它的方式有关吗?

This is possible in TypeScript 3.0. 这在TypeScript 3.0中是可能的。

To answer the question, I used ArgumentTypes<F> from 为了回答这个问题,我使用了ArgumentTypes<F>
this answer to: How to get argument types from function in Typescript . 这个答案:如何从Typescript中的函数中获取参数类型

Here's how: 这是如何做:
Demo on TypeScript playground 在TypeScript游乐场上演示

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Typescript - React,基于可选道具的条件回调道具类型 - Typescript - React, conditional callback prop type based on optional prop Typescript React:使用传递给同一组件的另一个道具有条件地将道具标记为可选或强制性 - Typescript React: Conditionally mark prop to optional or mandatory using another prop passed to same component 有条件地期望带有 Typescript 的 React 道具的字符串或 object 类型 - Conditionally expect a string or object type for React prop with Typescript typescript 反应,基于某个道具值的动态道具? - typescript react, dynamic props based on a certain prop value? 是否可以根据使用流的另一个道具的存在或值来计算类型以对组件道具做出反应? - Is it possible to compute type to react component props based on the presence or value of another prop using flow? React Typescript 儿童道具在类型道具中定义,但不知何故未拾取 - React Typescript children prop is defined in type props but somehow not picked up Typescript React - 从另一个通用道具推断道具类型 - Typescript React - Inferring prop type from another generic prop 带有可选 boolean 的 React TypeScript 道具被视为非 boolean 类型 - React TypeScript props with optional boolean is considered as a non boolean type 如何为React props定义TypeScript类型,只有在将prop A传递给组件时,才会接受prop B? - How do I define a TypeScript type for React props where prop B is only accepted if prop A is passed to a component? 当我们使用 React 和 Typescript 时,如何有条件地将可选道具传递给组件? - How to conditionally pass optional props to component when we use React with Typescript?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM