如何让not工具函数实现!操作符的Type narrowing类型收窄效果?
如何让自定义
not函数具备TypeScript类型收窄能力? 问题场景
我编写了用于判断输入是否为有效字符串的类型守卫函数及not工具函数:
export function isString(v: unknown): v is string { return typeof v === "string"; } export function not(v) { return v === false; }
在main函数中,我希望通过not做无效输入的提前返回,但遇到了类型收窄问题:
function main(input?: string) { if(not(isString(input))) { return } // 错误:此处无法将input识别为string类型 processString(input); } function processString(input: string) { // ... }
直接使用!操作符(if(!isString(input)))可以正常实现类型收窄,但我更倾向于not这种可读性更高的语法,想问能否配置not函数,让它具备和!相同的类型收窄能力?
解决方案
可以通过给not函数添加泛型类型谓词重载,让TypeScript识别其反向类型收窄逻辑。
修改后的not函数定义如下:
// 针对类型守卫的重载:反转类型判断结果 export function not<T>(v: v is T): v is not T; // 针对普通布尔值的重载 export function not(v: boolean): boolean; // 实现逻辑 export function not(v: unknown): boolean { return v === false; }
这样当你调用not(isString(input))时,TypeScript会理解:如果这个表达式返回true,则input is not string,因此在return之后的代码块中,input会被正确收窄为string类型,processString(input)就能正常通过类型检查。
如果需要支持更通用的类型守卫函数(比如接收参数的守卫),可以用更灵活的泛型定义:
type NegateGuard<T extends (x: any) => x is any> = T extends (x: infer U) => x is infer V ? (x: U) => x is Exclude<U, V> : never; // 接收类型守卫函数并返回反向守卫 export function not<T extends (x: any) => x is any>(guard: T): NegateGuard<T>; // 接收布尔值取反 export function not(v: boolean): boolean; export function not(v: unknown): unknown { if (typeof v === 'function') { return (x: unknown) => !v(x); } return !v; }
这种写法可以支持类似not(isString)这样直接传递守卫函数的场景,进一步提升代码灵活性。
内容的提问来源于stack exchange,提问作者Pratik Mehta
相关产品推荐
相关产品推荐

