创建含泛型、条件类型的TS接口时遇布尔属性类型错误
问题出在IDateRangeFilter的泛型参数WithCustomInputT默认值为true,而IFilterOptions中的date字段使用了未指定泛型参数的IDateRangeFilter<V>,TypeScript会自动将其推断为IDateRangeFilter<V, true>,因此withCustomInput只能接受true,传入false就会触发类型不兼容错误。
另外你当前的代码还有一个潜在问题:当withCustomInput=false时,to的类型是Partial<Prop2>(Prop2是空接口),此时to不能包含iconPosition这类不属于Prop2的属性,否则也会触发类型错误。
我们需要让IFilterOptions的date字段支持withCustomInput为true或false的两种情况,同时保证to的类型和withCustomInput的值联动。
方案1:扩展date字段为联合类型
修改IFilterOptions,让date接受IDateRangeFilter<V, true>和IDateRangeFilter<V, false>的联合类型,直接覆盖两种场景:
interface Prop1 { iconPosition: string; } interface Prop2 {} export interface IDateRangeFilter< V extends object, WithCustomInputT extends boolean = true > { to: Partial<WithCustomInputT extends false ? Prop2 : Prop1>; fromName: keyof V; withCustomInput: WithCustomInputT; } // 修改date字段为联合类型,支持两种布尔值场景 export interface IFilterOptions<KeyType extends keyof any, V extends object> { field?: KeyType; date?: IDateRangeFilter<V, true> | IDateRangeFilter<V, false>; } export type IFilterOptionsSingleType<T extends object> = IFilterOptions< keyof T, T >; interface Ifilter { ActivityStartDate: string; } // 正确示例:withCustomInput=true时,to可包含iconPosition export const ReferralsFilters1: IFilterOptionsSingleType<Ifilter>[] = [ { date: { to: { iconPosition: "end", }, fromName: "ActivityStartDate", withCustomInput: true, }, }, ]; // 正确示例:withCustomInput=false时,to为空对象或省略 export const ReferralsFilters2: IFilterOptionsSingleType<Ifilter>[] = [ { date: { to: {}, fromName: "ActivityStartDate", withCustomInput: false, }, }, ];
方案2:用类型别名封装联合类型
如果不想重复写联合类型,可以定义一个类型别名来统一两种场景:
// 新增类型别名,自动包含withCustomInput的两种情况 type DateRangeFilter<V extends object> = | IDateRangeFilter<V, true> | IDateRangeFilter<V, false>; export interface IFilterOptions<KeyType extends keyof any, V extends object> { field?: KeyType; date?: DateRangeFilter<V>; }
方案3:使用判别式联合类型(更简洁直观)
直接把IDateRangeFilter定义为判别式联合类型,不需要泛型参数,TypeScript会自动根据withCustomInput的布尔值推断to的类型:
interface Prop1 { iconPosition: string; } interface Prop2 {} // 定义判别式联合类型,通过withCustomInput作为判断标识 type IDateRangeFilter<V extends object> = | { to: Partial<Prop1>; fromName: keyof V; withCustomInput: true; } | { to: Partial<Prop2>; fromName: keyof V; withCustomInput: false; }; export interface IFilterOptions<KeyType extends keyof any, V extends object> { field?: KeyType; date?: IDateRangeFilter<V>; } export type IFilterOptionsSingleType<T extends object> = IFilterOptions< keyof T, T >; interface Ifilter { ActivityStartDate: string; } export const ReferralsFilters: IFilterOptionsSingleType<Ifilter>[] = [ { date: { to: { iconPosition: "end", }, fromName: "ActivityStartDate", withCustomInput: true, }, }, { date: { to: {}, fromName: "ActivityStartDate", withCustomInput: false, }, }, ];
这种方式无需泛型参数,TypeScript会严格根据withCustomInput的值约束to的结构,完全符合你想要的联动逻辑。
内容的提问来源于stack exchange,提问作者sarpere

