TypeScript递归类型守卫失效:深层嵌套受限内容未被拦截
解决TypeScript深层嵌套对象的受限内容类型守卫问题
要搞定深层嵌套对象里的受限内容检查,核心是实现递归遍历类型结构的类型检查逻辑。下面直接上可运行的方案:
1. 定义受限内容标记
先给受限内容加个唯一的类型标记,让TypeScript能精准识别它:
// 用独特属性标记受限内容,避免和业务属性冲突 type RestrictedContent = { __restricted: true }; // 示例:创建一个受限内容实例 const myRestrictedContent: RestrictedContent = { __restricted: true };
2. 实现递归类型检查
写一个递归类型HasRestrictedContent<T>,用来检查目标类型本身或其任意嵌套属性是否包含受限内容:
type HasRestrictedContent<T> = // 先判断当前类型是不是受限内容 T extends RestrictedContent ? true : // 如果是对象(排除原始类型和函数),递归检查每个属性 T extends object ? { [K in keyof T]: HasRestrictedContent<T[K]> }[keyof T] : // 原始类型直接判定为无受限内容 false;
这个类型的逻辑很直接:
- 若
T本身就是RestrictedContent,返回true - 若
T是对象,遍历所有属性并递归检查,只要有一个属性包含受限内容,整个类型就返回true - 字符串、数字等原始类型直接返回
false
3. 构建类型守卫函数
基于上面的递归类型,构建能在编译时拦截受限内容的类型守卫:
// 只允许不包含任何受限内容的输入 type AllowedInput<T> = HasRestrictedContent<T> extends true ? never : T; function RestrictedContentGuard<T>(input: AllowedInput<T>): input is T { // 这里可以补充你原来的数组、空值等运行时检查逻辑 return true; }
4. 测试验证
现在测试各种场景,包括深层嵌套的情况:
// 正常输入:编译通过 const validInput = { grandparent: { parent: { child: "正常内容" } } }; RestrictedContentGuard(validInput); // 浅层受限:编译器报错 const shallowInvalid = { child: myRestrictedContent }; RestrictedContentGuard(shallowInvalid); // ❌ 类型错误 // 深层嵌套受限:编译器报错 const deepInvalid = { grandparent: { parent: { child: myRestrictedContent } } }; RestrictedContentGuard(deepInvalid); // ❌ 类型错误
补充优化
如果需要支持数组、空值(null/undefined),只需在HasRestrictedContent里补充对应分支:
type HasRestrictedContent<T> = T extends RestrictedContent ? true : T extends null | undefined ? false : T extends Array<infer U> ? HasRestrictedContent<U> : T extends object ? { [K in keyof T]: HasRestrictedContent<T[K]> }[keyof T] : false;
注意:类型层面是编译时检查,运行时的检查逻辑要和类型逻辑对应,比如递归遍历对象属性、数组元素,确保运行时也能兜底拦截。
内容的提问来源于stack exchange,提问作者MonkeyMagiic
相关产品推荐
相关产品推荐

