如何基于数组成员类型约束TypeScript组件Props类型?
需求:根据数组中是否包含特定类型成员,动态设置组件必填Props
现有类型定义
type TabA = {type: 'a', num: number} type TabB = {type: 'b', str: string} type Tab = TabA | TabB type DomainModuleTabGroup = { tabsCollection: Tab[] }
需求与问题
需要声明组件Props类型,使得仅当tabsCollection数组包含TabA类型成员时,额外的tabAStuff属性为必填项;若数组仅含TabB,则该属性可选或无需传入。
非数组场景下实现逻辑很直观:
type DomainModuleTabGroup = { tab: Tab } type ComponentProps<T extends Tab> = { tab: T } & (T extends TabA ? { tabAStuff: number } : { tabAStuff?: never })
但数组场景下直接尝试的方法均无效,例如:
type ComponentProps<T extends DomainModuleTabGroup> = { module: T // 语法错误 other: 'a' in T['tabsCollection'][number]['type'] ? 'other a' : 'other b' // 语法合法但逻辑不成立 other: T['tabsCollection'][number] extends TabA ? 'other a' : 'other b' other: T['tabsCollection'][number]['type'] extends 'a' ? 'other a' : 'other b' } const domainMTG: DomainModuleTabGroup = { tabsCollection: [{ type: 'a', num: 1 }] } // 报错:extends判断结果为false,无法赋值"other a" const mtgProps: ComponentProps<typeof domainMTG> = { module: domainMTG, other: "other a" }
注:无法修改或扩展
Tab及DomainModuleTabGroup类型。
解决方案
问题核心是:直接使用T['tabsCollection'][number]会被解析为TabA | TabB联合类型,导致extends判断无法精准识别数组中是否包含TabA。
可以通过辅助类型结合类型提取实现需求,让TypeScript精准推断数组元素的类型特征:
实现代码
// 辅助类型:判断数组是否包含TabA类型 type HasTabA<T extends Tab[]> = Extract<T[number], TabA> extends never ? false : true; type ComponentProps<T extends DomainModuleTabGroup> = { module: T } & (HasTabA<T["tabsCollection"]> extends true ? { tabAStuff: number } : { tabAStuff?: never });
验证示例
// 仅含TabA:tabAStuff必填 const tabAOnlyGroup = { tabsCollection: [{ type: 'a', num: 1 }] as const }; const propsA: ComponentProps<typeof tabAOnlyGroup> = { module: tabAOnlyGroup, tabAStuff: 123 // 不填会触发类型报错 }; // 仅含TabB:tabAStuff可选或无需传入 const tabBOnlyGroup = { tabsCollection: [{ type: 'b', str: 'test' }] as const }; const propsB: ComponentProps<typeof tabBOnlyGroup> = { module: tabBOnlyGroup // 可省略tabAStuff,若传入只能赋值为undefined }; // 混合TabA与TabB:tabAStuff必填 const mixedGroup = { tabsCollection: [{ type: 'a', num: 1 }, { type: 'b', str: 'test' }] as const }; const propsMixed: ComponentProps<typeof mixedGroup> = { module: mixedGroup, tabAStuff: 456 // 必填 };
关键说明
- 使用
as const断言让TypeScript精准推断数组元素的具体类型,而非宽泛的Tab联合类型; HasTabA通过Extract<T[number], TabA>提取数组中属于TabA的元素,若结果为never则说明数组不含TabA;- 条件类型根据
HasTabA的结果,动态控制tabAStuff的必填性。
内容的提问来源于stack exchange,提问作者Jonathan Tuzman
相关产品推荐
相关产品推荐

