如何在React复合组件中使用Flow.js类型并保留必填Props?
解决React复合组件中Flow.js类型检查的必填属性问题
这确实是复合组件模式下Flow类型校验的典型痛点——既要保持子组件的必填属性约束,又要让Flow认可父组件会注入这些属性。下面给你两个可行的方案,完全符合你的需求(不传递组件类、不用渲染属性、保持title必填):
方案1:给TitleProvider定义子组件的类型约束
核心思路是让Flow明确知道:TitleProvider的子组件一定会被注入title属性,所以子组件的必填title在这个场景下是被满足的。
先修正TitleProvider的类型定义:
// 先定义一个类型,代表需要接收title注入的组件 type ComponentRequiringTitle = React.ElementType<{ title: string }>; // 定义TitleProvider的Props,限制子元素必须是符合上面类型的组件实例 type TitleProviderProps = { children: React.Element<ComponentRequiringTitle>; }; class TitleProvider extends React.Component<TitleProviderProps> { render() { // 这里cloneElement注入title,Flow会认可这个操作 return React.cloneElement(this.props.children, { title: 'Foo' }); } } // 你的A组件保持原类型不变 type AProps = { title: string }; const A = ({ title }: AProps) => <span>{title}</span>;
这样使用的时候:
- 当你写
<TitleProvider><A /></TitleProvider>,Flow不会报错,因为它知道TitleProvider会给A注入title; - 但如果你直接写
<A />,Flow依然会提示缺少必填的title属性,完美保留了组件的约束。
方案2:用Flow的$Diff工具类型做精准适配
如果你的子组件有更多额外属性,或者你想针对特定组件做更精准的类型控制,可以用Flow的$Diff工具类型,它能帮你移除子组件类型中的某个必填属性,告诉Flow这个属性会由父组件注入。
示例代码:
// A组件保持原类型,title必填,subtitle可选 type AProps = { title: string; subtitle?: string }; const A = ({ title, subtitle }: AProps) => ( <span>{title}{subtitle && ` - ${subtitle}`}</span> ); // 用$Diff移除AProps中的title,得到子组件在TitleProvider中需要的属性类型 type APropsWithoutTitle = $Diff<AProps, { title: string }>; // 定义TitleProvider的Props,子元素是仅需APropsWithoutTitle的组件实例 type TitleProviderProps = { children: React.Element<React.ElementType<APropsWithoutTitle>>; }; class TitleProvider extends React.Component<TitleProviderProps> { render() { return React.cloneElement(this.props.children, { title: 'Foo' }); } }
这个方案的优势是更灵活,比如你可以给A传递其他可选属性:
<TitleProvider> <A subtitle="Bar" /> {/* Flow不会要求传title,因为知道会被注入 */} </TitleProvider>
同样,直接使用<A subtitle="Bar" />时,Flow还是会提示缺少必填的title。
额外注意点
- 如果你的TitleProvider需要支持多个子组件,那你需要遍历
React.Children.map来给每个子组件注入属性,同时类型定义也要调整为接受React.Node,并在类型中声明每个子元素都符合需要注入属性的类型; - 上面的示例用了class组件的TitleProvider,如果是函数组件,写法类似,只需要把Props类型传给函数组件的泛型即可。
内容的提问来源于stack exchange,提问作者Martin Kadlec
相关产品推荐
相关产品推荐

