簡體   English   中英

如何在功能組件中使用 React Typescript 鍵入任何參數

[英]How to type any param with React Typescript in Functional Component

我有一個現有的 javascript 組件:

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

export default RenderState

我正在嘗試將其轉換為打字稿並且到目前為止:

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正在尋找一個字面上稱為“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>)}
    />
  </>
}

像您這樣的 Sonds 需要在您的類型上使用索引簽名。 一種天真的方法是

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

但是,這不會編譯 - 因為接口上的索引簽名要求所有命名屬性( 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 :

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 )。 但是,它無法使用 rest 解構進行編譯,如原始代碼片段所示:

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]

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM