如何根据React组件的Feature参数动态设置TS Prop可选性?
动态控制React组件属性必填性的类型实现
需求背景
现有一个React组件,接收Feature类型的单个字符串或数组作为feature属性,同时包含三个分别对应不同Feature的属性:requiredPropForFeature1、requiredPropForFeature2、requiredPropForFeature3。需要根据传入的feature值,动态设置属性的必填性:
- 传入
feature='feature1'时,仅requiredPropForFeature1必填,其余可选 - 传入
feature=['feature1','feature2']时,前两个属性必填,第三个可选 - 以此类推,确保编译时类型检查生效,避免大量运行时判断
原方案问题
之前的泛型实现仅支持单个Feature值,当传入数组类型的feature时,所有属性会变为可选,无法满足需求。
解决方案
通过类型映射和条件类型,分别处理单个Feature和Feature数组的情况,精准推导必填属性:
完整代码实现
type Feature = "feature1" | "feature2" | "feature3"; // 定义原始属性集合(不含feature) interface OriginalFeatureProps { requiredPropForFeature1: number; requiredPropForFeature2: () => void; requiredPropForFeature3: string; } // 建立Feature与对应属性的映射关系 type FeatureToPropMap = { feature1: 'requiredPropForFeature1'; feature2: 'requiredPropForFeature2'; feature3: 'requiredPropForFeature3'; }; // 根据传入的Feature类型(单个或数组)提取必填属性键 type RequiredPropKeys<T extends Feature | Feature[]> = T extends Feature ? FeatureToPropMap[T] : T extends Array<infer U> ? U extends Feature ? FeatureToPropMap[U] : never : never; // 生成最终的组件Props类型:必填属性强制要求,其余设为可选 type FeatureWrapperProps<T extends Feature | Feature[]> = { feature: T; } & Required<Pick<OriginalFeatureProps, RequiredPropKeys<T>>> & Partial<Pick<OriginalFeatureProps, Exclude<keyof OriginalFeatureProps, RequiredPropKeys<T>>>>; // 组件定义 const FeatureWrapper = <T extends Feature | Feature[]>({ feature, requiredPropForFeature1, requiredPropForFeature2, requiredPropForFeature3 }: FeatureWrapperProps<T>) => { // 组件业务逻辑 return null; };
类型逻辑说明
- 拆分属性与feature:将原始属性和
feature分离,让类型推导更清晰 - Feature映射表:
FeatureToPropMap统一管理Feature和对应属性的关联,避免重复的条件判断 - 提取必填属性键:
RequiredPropKeys通过条件类型,分别处理单个Feature和数组场景,自动提取所有需要必填的属性键 - 组合最终Props:用
Required确保指定属性必填,Partial将其余属性设为可选,组合成符合需求的Props类型
验证示例
// 单个feature1:仅requiredPropForFeature1必填,其余可选 <FeatureWrapper feature="feature1" requiredPropForFeature1={1} />; // 合法 <FeatureWrapper feature="feature1" />; // 编译报错:缺少requiredPropForFeature1 // 数组feature1+feature2:前两个属性必填 <FeatureWrapper feature={["feature1", "feature2"]} requiredPropForFeature1={1} requiredPropForFeature2={() => {}} />; // 合法 <FeatureWrapper feature={["feature1", "feature2"]} requiredPropForFeature1={1} />; // 编译报错:缺少requiredPropForFeature2 // 三个Feature全传:所有属性必填 <FeatureWrapper feature={["feature1", "feature2", "feature3"]} requiredPropForFeature1={1} requiredPropForFeature2={() => {}} requiredPropForFeature3="test" />; // 合法
内容的提问来源于stack exchange,提问作者Riptide
相关产品推荐
相关产品推荐

