javascript - 如何在功能组件中使用 React Typescript 键入任何参数

标签 javascript reactjs typescript types react-props

我有一个现有的 javascript 组件:

const RenderState = ({ state, else: elseChild = undefined, ...states }) => {
  if (state && states[state]) return states[state]
  if (elseChild) return elseChild
  return null
}

export default RenderState

我正在尝试将它转换为 typscript,到目前为止:

import React from 'react'

interface Props {
  state: string
  else?: JSX.Element
  any: JSX.Element
}

const RenderState: React.FC<Props> = ({ state, else: elseChild = undefined, ...states }) => {
  if (state && states[state]) return states[state]
  if (elseChild) return elseChild
  return null
}

export default RenderState

我遇到的问题当然是any: JSX.Element正在寻找字面上称为“任何”的 Prop ,而我想允许任何 Prop 作为 JSX 元素,例如 custom在下面的例子中

这是该组件的一个示例用例:

import React from 'react'
import RenderState from './RenderState'

const MyComp = () => {
  const [state, setState] = React.useState<string | null>(null)
  <>
    <Button onClick={()=>{setState(null)}}>Default</Button>
    <Button onClick={()=>{setState('custom')}}>Custom</Button>
    <RenderState
      state={state}
      custom={(<p>Some custom content here...</p>)}
      else={(<p>Some default content here...</p>)}
    />
  </>
}

最佳答案

听起来你需要在你的类型上有索引签名。 一个天真的方法是

interface Props {
  state: string
  else?: JSX.Element
  [key: string]: JSX.Element
}

但是,这不会编译 - 因为接口(interface)上的索引签名要求所有命名属性(stateelse)与其兼容。

相反,您可以以类型交集的形式重写它:

type Props = {
  state: string
  else?: JSX.Element
} & Record<string, JSX.Element>

这仍然无法编译,但给了我们一个线索。如果我们有一组众所周知的可能值而不是 string 作为键会怎样? 下一次迭代将是

type Key = "custom" | "another";

type Props = {
  state: Key | null
  else?: JSX.Element
} & Record<Key, JSX.Element>

这看起来更好。但是我们如何使它可重用,以便同一个组件可以用于不同的可能键列表?让我们让它通用!

所以最后的代码:

type Props<Key extends string> = {
  state: Key | null
  else?: JSX.Element
} & Record<Key, JSX.Element>

您还需要使组件成为通用函数:

function RenderState<Key>(props: Props<Key>) { ... }

并在您的应用中使用它:

    const [state, setState] = React.useState<"custom" | null>(null);
    <RenderState
      state={state}
      custom={(<p>Some custom content here...</p>)}
      else={(<p>Some default content here...</p>)}
    />

编辑 1

这种方法允许在 RenderState 中编写 props[props.state](结果被推断为 JSX.Element)。 但是,它无法使用剩余解构进行编译,如原始代码片段所示:

const {state, else: elseEl, ...rest} = props;
rest[props] // TS error here

它揭示了我们类型定义中的一个缺陷。我们需要确保 state 值不包含 "state""else" 文字,以避免类型冲突。

更新后的类型是


type Props<Key extends string> = {
  state: Exclude<Key, "state" | "else"> | null
  else?: JSX.Element
} & Record<Key, JSX.Element>

现在应该编译好了

const {state, else: elseEl, ...rest} = props;
rest[props]

关于javascript - 如何在功能组件中使用 React Typescript 键入任何参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65010586/

相关文章:

javascript - 如何通过ajax获取UTF-8格式的数据

reactjs - react-icons应用线性梯度

Typescript + Webpack 库生成 "ReferenceError: self is not defined"

typescript - 为什么函数在 vue 3 设置 block 中立即执行

typescript - ts-jest 不识别 es6 导入

javascript - 使用变量作为名称来访问另一个数组的嵌套元素

javascript - innerHTML 更改后 HTML 上传表单重置

javascript - Node 文件系统在后路由上创建目录和文件

javascript - 如何在不显示超链接的情况下制作可点击的图像?

javascript - react - 未捕获的类型错误 : Cannot read property 'setState' of undefined