如何让React子组件感知父组件Hidden的when条件校验结果?
如何让React的组件传递类型校验信息给子组件
我有一个<Hidden>组件,它会根据when属性条件性隐藏子组件(when=true时子组件被隐藏)。但当子组件要求必填prop时,比如<ID>组件需要传入string类型的id,即使我在when里校验了id已定义,TypeScript仍然会报错——因为子组件不知道此时id已经是确定存在的。我需要让<Hidden>的when条件像if判断一样,让子组件感知到props的类型已经被收窄。
原代码中的报错场景:
// App.tsx export default function App() { let id: string | undefined = undefined; if (Math.random() >= 0.5) { id = "some-id"; } return ( <Hidden when={!!id}> {/* TypeScript报错:id可能为undefined,不满足ID组件的string类型要求 */} <ID id={id} /> </Hidden> ); } // Hidden.tsx import { FunctionComponent } from 'react'; type HiddenProps = { when: boolean }; export const Hidden: FunctionComponent<HiddenProps> = (props) => { const { children, when } = props; return when ? <>{children}</> : null; }; // ID.tsx import { FunctionComponent } from 'react'; type IDProps = { id: string }; export const ID: FunctionComponent<IDProps> = (props) => { const { id } = props; return <div>{id}</div>; };
解决方案:把改成类型守卫组件
要实现这个效果,需要给<Hidden>组件的类型做泛型约束,让when的条件和子组件的上下文建立类型关联,本质上是让Hidden成为一个类型守卫组件。具体修改如下:
1. 重写Hidden组件的类型与实现
// Hidden.tsx import { FunctionComponent, ReactNode } from 'react'; // 泛型Props:T是需要校验的上下文类型 type HiddenProps<T> = { // when作为类型守卫函数,收窄上下文的类型 when: (context: T) => context is Exclude<T, undefined | null>; // 需要校验的上下文值 context: T; // children是接收收窄后上下文的函数,确保子组件能拿到确定类型的值 children: (validContext: Exclude<T, undefined | null>) => ReactNode; }; export const Hidden = <T,>(props: HiddenProps<T>) => { const { when, context, children } = props; // 只有when校验通过时,才渲染子组件并传入已校验的上下文 return when(context) ? <>{children(context)}</> : null; };
2. 修改App组件的使用方式
// App.tsx export default function App() { let id: string | undefined = undefined; if (Math.random() >= 0.5) { id = "some-id"; } return ( <Hidden context={id} // 明确类型守卫:当val不为空时,它是string类型 when={(val): val is string => !!val} > {/* 这里的validId已经被TypeScript推断为string类型,不会报错 */} {(validId) => <ID id={validId} />} </Hidden> ); }
方案说明
这种方式通过函数式children配合类型守卫,让TypeScript能够准确推断出传入子组件的props已经是必填的确定类型,彻底消除了报错。相比直接用断言,这种方案更安全——类型守卫会在运行时也做一次校验,同时保证了类型的正确性。
内容的提问来源于stack exchange,提问作者Aerophite
相关产品推荐
相关产品推荐

