TypeScript中的类型安全谓词函数
我的目标是在TypeScript中编写谓词函数(TypeScript中的类型安全谓词函数,typescript,predicate,Typescript,Predicate,我的目标是在TypeScript中编写谓词函数(isNull和isUndefined),这些函数满足以下条件: 可以独立使用:array.filter(isNull) 可以逻辑组合:array.filter(和(非(isNull)、非(isUndefined)) 使用类型保护,以便TypeScript知道例如array.filter(isNull)的返回类型将是null[] 组合谓词可以提取到新的谓词函数中,而无需中断类型推断:const isNotNull=not(isNull) 前两个条件很
isNull
和isUndefined
),这些函数满足以下条件:
array.filter(isNull)
array.filter(和(非(isNull)、非(isUndefined))
array.filter(isNull)
的返回类型将是null[]
const isNotNull=not(isNull)
type谓词=(i:any)=>boolean;
常量和=(p1:谓词,p2:谓词)=>
(i:任何)=>p1(i)和p2(i);
常量or=(p1:谓词,p2:谓词)=>
(i:任何)=>p1(i)| | p2(i);
常量not=(p:谓词)=>
(i:任何)=>!p(i);
常量isNull=(i:any)=>
i==null;
常量isUndefined=(i:any)=>
i==未定义;
const items=[“foo”,null,123,未定义,true];
const filtered=items.filter(and(not(isNull)、not(isUndefined));
console.log(过滤);
但由于此处未使用类型保护,TypeScript假定变量筛选后的
与项
具有相同的类型,即(字符串、数字、布尔值、null、未定义)[
,而实际上现在应该是(字符串、数字、布尔值)[
所以我添加了一些打字脚本魔术:
type Diff=T扩展U?从不:T;
类型谓词=(i:i)=>i是O;
常量和=(p1:谓词,p2:谓词)=>
(i:i):i是(O1和O2)=>p1(i)和p2(i);
常量or=(p1:谓词,p2:谓词)=>
(i:i):i是(O1 | O2)=>p1(i)| p2(i);
常量not=(p:谓词)=>
(i:i):我是(Diff)=>!p(i);
常量isNull=(i:i | null):i为null=>
i==null;
常量未定义=(i:i |未定义):i未定义=>
i==未定义;
现在它似乎可以工作了,过滤后的
被正确地简化为类型(字符串、数字、布尔)[
但是由于not(isNull)
可能经常被使用,我想将其提取到一个新的谓词函数中:
const isNotNull=not(isNull);
虽然这在运行时非常有效,但不幸的是它没有编译(启用严格模式的TypeScript 3.3.3):
类型为“(i:i | null)=>i为null”的参数不能分配给类型为“Predicate”的参数。
类型谓词“i为null”不能赋值给“i为{}”。
类型“null”不可分配给类型“{}”。ts(2345)
因此,我猜想当使用谓词作为数组过滤器
方法的参数时,TypeScript可以从数组中推断I
的类型,但是当将谓词提取到单独的函数中时,这将不再起作用,TypeScript返回到基本对象类型{}
,这会破坏一切
有办法解决这个问题吗?在定义
isNotNull
函数时,有什么技巧可以说服TypeScript坚持使用泛型类型I
,而不是将其解析为{}
?或者这是TypeScript的一个限制,目前无法完成?这就是您要找的吗
const isNotNull=not(isNull)代码>从上下文传递类型信息。这段代码编译得很好
// c: (string | number)[]
let c = [1, 2, 'b', 'a', null].filter(not<number | string | null, null>(isNull));
/c:(字符串|数字)[]
设c=[1,2,'b','a',null].filter(not(isNull));
No。这修复了编译器错误,但破坏了类型安全。如果使用此函数过滤数组,则返回值为any[]
这是一个很酷的主意!您使用什么TS版本?您的代码现在在TS游乐场中运行良好<代码>设a2=[1,2,'sdfsf',null]。筛选器(isNotNull);//让a2:(string | number)[
我在严格模式下使用最新的Typescript 3.3.3。至少启用TS Playway中的strictNullChecks
选项以重现问题。它不会编译,在您的示例中,将鼠标悬停在a2
上会显示错误的类型never[]
。TS的一个缺点是不能将用户定义的类型保护与标准返回类型混合使用。我不确定您想做什么是可能的,您需要从头定义isNotNull
,而不是编写它@kayahr,我认为,这是编译器错误,因为在非严格模式下,编译器会按预期检测类型
// c: (string | number)[]
let c = [1, 2, 'b', 'a', null].filter(not<number | string | null, null>(isNull));