TypeScript中如何实现支持可变数量泛型参数的React条件渲染组件
通用版实现方案
核心思路
完全可以实现支持任意数量属性的通用版本,核心依赖TypeScript的可变元组泛型和递归类型收窄能力,可以自动推导传入数组每个元素的原始类型,过滤掉null/undefined类型完成自动收窄,不需要为不同参数数量单独定义组件。
完整代码实现
import type { ReactNode } from "react"; // 基础类型定义 export type Maybe<T> = T | undefined | null; // 类型工具:将Maybe元组的每个元素收窄为非空类型 type ExcludeNullishFromTuple<T extends Maybe<any>[]> = { [K in keyof T]: T[K] extends Maybe<infer U> ? U : never; }; // 通用Only组件,支持任意长度的when数组 export function Only<T extends Maybe<any>[]>(props: { when: T; children: ReactNode | ((when: ExcludeNullishFromTuple<T>) => ReactNode); }) { const { when, children } = props; // 检查所有元素都为真值 const isAllTruthy = when.every(item => Boolean(item)); if (!isAllTruthy) return null; return ( <> {typeof children === "function" ? children(when as ExcludeNullishFromTuple<T>) : children} </> ); }
使用示例
直接传入任意长度的数组即可,回调参数会自动收窄为非空类型,无需额外的非空断言:
import { useState } from "react"; const MyComponent = (props: { value1: number; value2: string; value3: boolean }) => ( <> <div>Value1: {props.value1}</div> <div>Value2: {props.value2}</div> <div>Value3: {props.value3 ? "是" : "否"}</div> </> ); export function MyPage() { const [value1, setValue1] = useState<number>(); const [value2, setValue2] = useState<string>(); const [value3, setValue3] = useState<boolean>(); setTimeout(() => { // 模拟异步请求 setValue1(42); setValue2("foo"); setValue3(true); }, 1000); return ( <div> <Only when={[value1, value2, value3]}> {([value1, value2, value3]) => ( <MyComponent value1={value1} value2={value2} value3={value3} /> )} </Only> </div> ); }
可选优化:对象传参版本
如果觉得数组解构不够直观,还可以实现支持传入对象的版本,使用时可以直接按属性名解构,更适合参数较多的场景:
// 对象版本类型工具 type ExcludeNullishFromObject<T extends Record<string, Maybe<any>>> = { [K in keyof T]: T[K] extends Maybe<infer U> ? U : never; }; export function OnlyObject<T extends Record<string, Maybe<any>>>(props: { when: T; children: ReactNode | ((when: ExcludeNullishFromObject<T>) => ReactNode); }) { const { when, children } = props; const isAllTruthy = Object.values(when).every(item => Boolean(item)); if (!isAllTruthy) return null; return ( <> {typeof children === "function" ? children(when as ExcludeNullishFromObject<T>) : children} </> ); } // 使用示例 <OnlyObject when={{ value1, value2, value3 }}> {({ value1, value2, value3 }) => ( <MyComponent value1={value1} value2={value2} value3={value3} /> )} </OnlyObject>
内容的提问来源于stack exchange,提问作者arslancharyev31
相关产品推荐
相关产品推荐

