如何创建可自动推导子组件类型的泛型React Context?
React泛型Context实现子组件自动类型推导方案
完全可行,核心是让TabsRoot的泛型类型自动传递给子组件,无需手动为TabsHeader指定泛型。你之前的实现问题在于TabsRoot的children被定义为React.ReactNode,无法携带泛型信息,导致子组件无法自动推导类型。下面是修改后的完整实现:
完整代码实现
import React, { Dispatch, SetStateAction, useState, useContext } from 'react'; type Headers = 'Foo' | 'Bar' | 'Baz'; const defaultValue: Headers = 'Foo'; type TabsContextProps<T> = { activeTab: T; setActiveTab: Dispatch<SetStateAction<T>>; }; const TabsContext = React.createContext<TabsContextProps<any> | undefined>(undefined); // 改造TabsRootProps,让children成为接收上下文的函数(Render Props模式) type TabsRootProps<T> = { defaultValue: T; children: (context: TabsContextProps<T>) => React.ReactNode; }; export function TabsRoot<T>({ defaultValue, children }: TabsRootProps<T>) { const [activeTab, setActiveTab] = useState<T>(defaultValue); const contextValue: TabsContextProps<T> = { activeTab, setActiveTab, }; return ( <TabsContext.Provider value={contextValue}> {children(contextValue)} </TabsContext.Provider> ); } function useTabsRootContext<T>(): TabsContextProps<T> { const context = useContext(TabsContext); if (!context) { throw new Error('useTabsRootContext must be used inside TabsRoot'); } return context as TabsContextProps<T>; } // TabsHeader无需手动指定泛型,自动从Context推导类型 const TabsHeader = <T>({ value }: { value: T }) => { const { activeTab } = useTabsRootContext<T>(); if (activeTab !== value) { return null; } return <p>Im Active</p>; }; // 理想用法:子组件自动推导类型,错误值触发TypeScript报错 const Tabs = () => { return ( <TabsRoot defaultValue={defaultValue}> {() => ( <> <TabsHeader value="Baz" /> <TabsHeader value="error" /> {/* TypeScript直接报错:类型"error"不能赋值给类型Headers */} </> )} </TabsRoot> ); };
关键改动说明
- Render Props传递泛型:将
TabsRoot的children改为函数,TabsRoot的泛型T会通过defaultValue自动推导,子函数内部的所有组件都能共享该类型。 - 修复状态初始化:原代码中
useState未使用defaultValue,导致初始activeTab为undefined,现在修正为用defaultValue初始化。 - 简化TabsHeader类型:去掉手动指定泛型的逻辑,直接从
useTabsRootContext推导类型,确保value与上下文的activeTab类型完全匹配。
这种方案既实现了类型自动推导,又保证了类型安全性,完全符合你期望的用法。
内容的提问来源于stack exchange,提问作者Martin Hansson
相关产品推荐
相关产品推荐

