如何创建TypeScript的NonDate工具类型?深度检测Date转never
解决方案
可以通过带深度控制的递归类型实现需求,既避免循环报错,又能灵活控制检测深度(默认6层,可按需调整)。核心思路是递归遍历类型的每一层,同时跟踪当前深度,一旦检测到Date就标记为存在,超过设定深度则停止递归。
实现代码
// 辅助类型:检测类型T中是否存在Date(支持深度控制) type _HasDate<T, Depth extends number = 6, CurrentDepth extends any[] = []> = // 超过指定深度,停止递归,视为无Date CurrentDepth['length'] extends Depth ? false : // 当前类型是Date,直接返回true T extends Date ? true : // 当前是数组,递归检测数组元素 T extends Array<infer U> ? _HasDate<U, Depth, [...CurrentDepth, 0]> : // 当前是对象(排除Date,因为已经判断过),递归检测每个属性 T extends object ? { [K in keyof T]: _HasDate<T[K], Depth, [...CurrentDepth, 0]> }[keyof T] extends true ? true : false : // 基础类型,无Date false; // 最终工具类型:存在Date则返回never,否则返回原类型 export type NonDate<T, Depth extends number = 6> = _HasDate<T, Depth> extends true ? never : T;
代码解释
- 深度控制:用
CurrentDepth元组的长度跟踪当前递归深度,当长度等于Depth(默认6)时停止递归,避免无限循环和类型溢出。 - 类型分支处理:
- 优先判断
T是否为Date,是则直接返回true - 数组类型:递归检测数组的元素类型
U - 对象类型:遍历所有属性,只要有一个属性检测到
Date,就返回true - 基础类型(number/string/boolean等):返回
false
- 优先判断
- NonDate逻辑:如果
_HasDate返回true(存在Date),则返回never,否则保留原类型T。
测试验证
代入你的测试用例,结果完全符合预期:
type Test1 = NonDate<number>; // number type Test2 = NonDate<string>; // string type Test3 = NonDate<Date>; // never type Test4 = NonDate<boolean>; // boolean type Test5 = NonDate<Date[]>; // never type Test6 = NonDate<number[]>; // number[] type Test7 = NonDate<{}>; // {} type Test8 = NonDate<{ a: Date; b: string }>; // never type Test9 = NonDate<{ a: Date; b: number }>; // never type Test10 = NonDate<{ a: number; b: string }>; // { a: number; b: string } type Test11 = NonDate<{ a: { b: Date } }>; // never type Test12 = NonDate<{ a: string; b: string; test: Date[] }>; // never type Test13 = NonDate<{ a: string; b: string; test: number[] }>; // { a: string; b: string; test: number[] }
扩展说明
如果需要调整检测深度,只需在使用时传入第二个参数,比如检测10层:
type DeepTest = NonDate<{ a: { b: { c: { d: { e: { f: { g: Date } } } } } }, 10>; // never
内容的提问来源于stack exchange,提问作者TJ Pavlu
相关产品推荐
相关产品推荐

