[英]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
字段,以及一個是AddEditJobsProps
或AddEditCustomersProps
的props
字段”。 但它沒有指定如果type
等於"job"
那么props
字段必須匹配AddEditJobsProps
。 為此,您需要更明確地說明:
export type SidebarProps =
| {
type: "job";
props: AddEditJobsProps;
}
| { type: "customer"; props: AddEditCustomersProps };
這使用聯合類型來確保SidebarProps
具有一種或另一種完整且有效的形狀。
通過這些更改,不僅Sidebar
中的 TS 錯誤消失了,而且當您在另一個組件中呈現它時,您將獲得預期的正確 TS 檢查。 如果type
是"job"
但props
道具沒有AddEditJobsProps
的預期形狀,你會得到一個錯誤。 在這個沙箱中親自嘗試一下:
我認為答案是這里的“動態組件”模式讓事情變得困難。 人類和計算機都難以理解,導致代碼難以閱讀和維護,並且 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.