如何基于两个泛型类型与布尔值抛出TypeScript错误
实现TypeScript泛型配置的类型约束规则
核心思路
通过自定义类型工具和条件类型,根据someBoolean、泛型T和R的组合,在编译阶段对不符合规则的配置抛出错误。
步骤1:定义类型判断工具
先创建三个基础类型工具,用来区分泛型属于规则中的string、number还是object(非原始引用类型):
// 判断是否为 string 类型 type IsString<T> = T extends string ? true : false; // 判断是否为 number 类型 type IsNumber<T> = T extends number ? true : false; // 判断是否为引用类型(对应规则中的 object 类别) type IsObject<T> = T extends string | number ? false : true;
步骤2:方案一:用条件类型直接约束配置
通过ValidConfig条件类型,根据someBoolean的取值分支实现规则判断,不符合规则的分支返回never类型,触发编译错误:
interface BaseConfig<T, R> { someBoolean: boolean; } type ValidConfig<T, R, B extends boolean> = // someBoolean 为 false 时的规则 B extends false ? (IsString<T> extends true ? IsString<R> extends true ? BaseConfig<T, R> : never : IsNumber<T> extends true ? IsNumber<R> extends true ? BaseConfig<T, R> : never : IsObject<T> extends true ? (IsString<R> extends true || IsNumber<R> extends true ? BaseConfig<T, R> : never) : never) // someBoolean 为 true 时的规则 : (IsString<T> extends true ? IsString<R> extends true ? BaseConfig<T, R> : never : IsNumber<T> extends true ? IsNumber<R> extends true ? BaseConfig<T, R> : never : IsObject<T> extends true ? BaseConfig<T, R> : never); // 合法示例 const valid1: ValidConfig<string, string, false> = { someBoolean: false }; const valid2: ValidConfig<{ name: string }, number, false> = { someBoolean: false }; const valid3: ValidConfig<{ name: string }, { age: number }, true> = { someBoolean: true }; // 非法示例(编译报错) // const invalid1: ValidConfig<string, number, false> = { someBoolean: false }; // const invalid2: ValidConfig<{ name: string }, { age: number }, false> = { someBoolean: false };
步骤3:方案二:用允许组合元组约束
把所有允许的组合整理成元组联合类型,通过判断当前组合是否在允许列表中来约束配置,维护更直观:
// 定义所有允许的组合([someBoolean, T, R]) type AllowedCombinations = [false, string, string] | [false, number, number] | [false, object, string] | [false, object, number] | [true, string, string] | [true, number, number] | [true, object, string] | [true, object, number] | [true, object, object]; // 判断当前组合是否合法 type IsAllowed<B extends boolean, T, R> = [B, T, R] extends AllowedCombinations ? true : false; // 配置接口,通过_guard属性触发错误 interface IConfig<B extends boolean, T, R> { someBoolean: B; // 不合法时_guard类型为never,无法赋值 _guard: IsAllowed<B, T, R> extends true ? unknown : never; } // 合法示例 const validConfig: IConfig<false, string, string> = { someBoolean: false, _guard: undefined }; // 非法示例(编译报错) // const invalidConfig: IConfig<false, string, number> = { someBoolean: false, _guard: undefined };
关键说明
- 方案一适合需要动态逻辑的约束,方案二更适合规则固定、需要直观维护的场景。
IsObject类型会把所有非string/number的类型(包括接口、自定义对象、数组等)判定为规则中的object类别,符合需求。
内容的提问来源于stack exchange,提问作者Andrew Allen
相关产品推荐
相关产品推荐

