簡體   English   中英

Typescript 中動態 React 組件的條件類型

[英]Conditional types for a dynamic React component in Typescript

嘗試創建一個動態的 React 組件。 根據所選組件有條件地傳遞正確的 propType 的正確方法是什么。 這是我到目前為止我在這一行上收到的錯誤<SelectComponent {...props.props} />因為道具與組件不匹配:

export interface SidebarProps {
    type: keyof typeof components,
    props: AddEditJobsProps | AddEditCustomersProps
}

const components = {
  job: AddEditJobs,
  customer: AddEditCustomers
};

export default function Sidebar(props: SidebarProps) {
  const { open, toggle } = useToggle();
  const SelectComponent = components[props.type];

  return (
    <RightSidebar open={open} toggleDrawer={toggle}>
      <SelectComponent {...props.props} />
    </RightSidebar>
  );
}

編輯:道具添加any修復了錯誤,但是 Typescript 在類型檢查期間將無法將所選類型與相應的道具匹配,這是我希望在這里完成的。

export interface SidebarProps {
    type: keyof typeof components,
    props: AddEditJobsProps | AddEditCustomersProps | any
}

如果您堅持以這種方式保持動態,那么您可能應該這樣做。

正如我在評論中提到的,問題一是 TS 直到運行props.type知道props.type的值是什么,因此它無法有效地提前推斷它應該是什么。 為了解決這個問題,你需要一個簡單的舊條件來顯式渲染正確的組件:

export const Sidebar: React.FC<SidebarProps> = props => {
  const { open, toggle } = useToggle();

  let inner: React.ReactNode;
  if (props.type === "job") {
    inner = <AddEditJobs {...props.props} />;
  } else if (props.type === "customer") {
    inner = <AddEditCustomers {...props.props} />;
  }

  return (
    <RightSidebar open={open} toggleDrawer={toggle}>
      {inner}
    </RightSidebar>
  );
};

請注意,條件語句基本上斷言了該字段的值,這有助於 TS 推斷形狀的其余部分是什么並改進代碼時類型檢查。

問題二是您的SidebarProps界面過於寬松。

你有這個:

export interface SidebarProps {
    type: keyof typeof components,
    props: AddEditJobsProps | AddEditCustomersProps
}

這基本上是在告訴 Typescript“對象應該有一個匹配components一個鍵的type字段,以及一個是AddEditJobsPropsAddEditCustomersPropsprops字段”。 但它沒有指定如果type等於"job"那么props字段必須匹配AddEditJobsProps 為此,您需要更明確地說明:

export type SidebarProps =
  | {
      type: "job";
      props: AddEditJobsProps;
    }
  | { type: "customer"; props: AddEditCustomersProps };

這使用聯合類型來確保SidebarProps具有一種或另一種完整且有效的形狀。

通過這些更改,不僅Sidebar中的 TS 錯誤消失了,而且當您在另一個組件中呈現它時,您將獲得預期的正確 TS 檢查。 如果type"job"props道具沒有AddEditJobsProps的預期形狀,你會得到一個錯誤。 在這個沙箱中親自嘗試一下:

https://codesandbox.io/s/youthful-fog-8lq41

我認為答案是這里的“動態組件”模式讓事情變得困難。 人類和計算機都難以理解,導致代碼難以閱讀和維護,並且 Typescript 編譯器無法准確檢查。

這里使用的更好的模式是組件組合。 使<Sidebar>更通用,以便它不關心它呈現的子級,並且只處理打開/切換狀態。

export default const Sidebar: React.FC = ({children}) => {
  const { open, toggle } = useToggle();

  return (
    <RightSidebar open={open} toggleDrawer={toggle}>
      {children}
    </RightSidebar>
  );
}

然后,當你想渲染一個側邊欄時,你只需給它你想要它包裝的孩子:

<Sidebar>
  <AddEditJobs {...addEditJobsProps} />
</Sidebar>

// or

<Sidebar>
  <AddEditCustomers {...addEditCustomersProps} />
</Sidebar>

您將獲得准確而嚴格的類型檢查(因為 TS 將知道組件和道具的確切類型)並且您的代碼結構將更具可讀性和更易於遵循。

暫無
暫無

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

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