TypeScript可导出工具函数的类型守卫实现问题
正确实现TypeScript类型守卫工具函数的方案
1. 基础类型守卫(isNull、isFunction)
这类单一判断的工具函数,直接用类型谓词明确返回类型,就能让TS正确完成类型收窄:
isNull/ isUndefined
export function isNull(value: unknown): value is null { return value === null; } export function isUndefined(value: unknown): value is undefined { return value === undefined; } // 合并判断版 export function isNullOrUndefined(value: unknown): value is null | undefined { return isNull(value) || isUndefined(value); }
isFunction
如果只需判断普通可调用类型,直接用typeof判断即可,类型谓词泛型可以兼容不同函数类型:
export function isFunction<T extends Function>(value: unknown): value is T { return typeof value === 'function'; }
2. 解决isNullOrEmpty的类型收窄问题
你遇到的never类型问题,根源是直接把目标类型定义为{} | [] | null | undefined,TS无法反向推断“非空非空”的具体类型。正确做法是从排除法入手,先明确需要保留的类型,再定义精准的类型谓词:
// 辅助类型:定义“非空非空”的合法类型 type NonNullOrEmpty<T> = T extends null | undefined ? never : T extends object ? T extends Array<any> ? T extends { length: 0 } ? never : T : T extends Record<string, never> ? never : T : T; // 实现isNullOrEmpty,用Exclude反向定义类型谓词 export function isNullOrEmpty<T>(value: T): value is Exclude<T, NonNullOrEmpty<T>> { if (isNullOrUndefined(value)) return true; if (Array.isArray(value)) return value.length === 0; if (typeof value === 'object') return Object.keys(value).length === 0; // 如果需要把空字符串纳入判断,可添加:if (typeof value === 'string') return value === ''; return false; }
使用时,!isNullOrEmpty分支会正确推断出非空类型:
const arr: number[] | [] | null = [1,2,3]; if (!isNullOrEmpty(arr)) { arr.map(item => item * 2); // 类型推断为number[],无报错 }
3. isNullOrWhitespace的实现
同样用反向思维,先定义“非空白字符串”的类型,再写类型守卫:
// 辅助类型:标记非空白字符串 type NonWhitespaceString = string & { __nonWhitespace: never }; // 判断“是空/空白”的类型守卫 export function isNullOrWhitespace(value: unknown): value is null | undefined | '' | (string & { trim(): '' }) { if (isNullOrUndefined(value)) return true; if (typeof value !== 'string') return false; return value.trim() === ''; } // 更直观的反向判断:直接判断“非空白字符串” export function isNonWhitespaceString(value: unknown): value is NonWhitespaceString { return typeof value === 'string' && value.trim() !== ''; }
使用示例:
const str: string | null = ' hello '; if (isNonWhitespaceString(str)) { console.log(str.trim()); // str被推断为非空白字符串 }
关键技巧总结
- 避免宽泛的“空类型”定义:优先从反向明确需要保留的类型,用
Exclude或自定义类型排除无效值。 - 类型谓词要精准:结合运行时判断逻辑,让TS能准确关联类型和代码分支。
- 拆分复杂判断:把多条件的类型守卫拆成多个小判断(先判null/undefined,再判数组、对象),TS的类型分析会更准确。
内容的提问来源于stack exchange,提问作者C. Helling
相关产品推荐
相关产品推荐

