ama*_*ter 1 javascript types typescript reactjs 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
Run Code Online (Sandbox Code Playgroud)
我正在尝试将其转换为 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
Run Code Online (Sandbox Code Playgroud)
我遇到的问题当然any: JSX.Element是寻找一个字面上称为“any”的道具,而我想允许任何道具作为 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>)}
/>
</>
}
Run Code Online (Sandbox Code Playgroud)
Sonds 喜欢您的类型需要索引签名。一种天真的方法是
interface Props {
state: string
else?: JSX.Element
[key: string]: JSX.Element
}
Run Code Online (Sandbox Code Playgroud)
但是,这不会编译 - 因为接口上的索引签名要求所有命名属性(state和else)与其兼容。
相反,您可以以类型交集的形式重写它:
type Props = {
state: string
else?: JSX.Element
} & Record<string, JSX.Element>
Run Code Online (Sandbox Code Playgroud)
这仍然不会编译相同,但给了我们一个线索。如果string我们有一组众所周知的可能值而不是键呢?下一次迭代将是
type Key = "custom" | "another";
type Props = {
state: Key | null
else?: JSX.Element
} & Record<Key, JSX.Element>
Run Code Online (Sandbox Code Playgroud)
这看起来更好。但是我们如何使它可重用,以便相同的组件可以与不同的可能键列表一起使用?让我们让它通用!
所以最后的代码:
type Props<Key extends string> = {
state: Key | null
else?: JSX.Element
} & Record<Key, JSX.Element>
Run Code Online (Sandbox Code Playgroud)
您还需要使组件成为通用函数:
function RenderState<Key>(props: Props<Key>) { ... }
Run Code Online (Sandbox Code Playgroud)
并在您的应用中使用它:
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>)}
/>
Run Code Online (Sandbox Code Playgroud)
编辑 1
这种方法允许在props[props.state]内部写入RenderState(结果推断为JSX.Element)。但是,它无法通过 rest 解构进行编译,如原始代码片段所示:
const {state, else: elseEl, ...rest} = props;
rest[props] // TS error here
Run Code Online (Sandbox Code Playgroud)
它揭示了我们的类型定义中的一个缺陷。我们需要确保statevalue 不包含"state"和"else"文字,以避免类型冲突。
更新的类型将是
type Props<Key extends string> = {
state: Exclude<Key, "state" | "else"> | null
else?: JSX.Element
} & Record<Key, JSX.Element>
Run Code Online (Sandbox Code Playgroud)
现在这应该可以很好地编译
const {state, else: elseEl, ...rest} = props;
rest[props]
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
635 次 |
| 最近记录: |