我有一个现有的 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)上的索引签名要求所有命名属性(state
和 else
)与其兼容。
相反,您可以以类型交集的形式重写它:
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/